root/lm-sensors/trunk/kernel/busses/i2c-i801.c @ 545

Revision 545, 18.0 KB (checked in by frodo, 14 years ago)

mkpatch updates

* mkpatch now correctly works when kernel-side files do not yet exist.

I forgot to propagate a change in the i2c version.

* init* handling in mkpatch and compat.h
* New i801 defines added to mkpatch

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i801.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
5    Philip Edelbrock <phil@netroedge.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/*
23    This driver supports the Intel 82801AA and 82801AB
24    I/O Controller Hubs (ICH). They are similar to the PIIX4 and are part
25    of Intel's '810' chipset. See the doc/busses/i2c-i801 file for details.
26*/     
27
28/* Note: we assume there can only be one I801, with one SMBus interface */
29
30#include <linux/module.h>
31#include <linux/pci.h>
32#include <asm/io.h>
33#include <linux/kernel.h>
34#include <linux/stddef.h>
35#include <linux/sched.h>
36#include <linux/ioport.h>
37#include <linux/i2c.h>
38#include "version.h"
39#include "compat.h"
40
41#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54))
42#include <linux/bios32.h>
43#endif
44
45/* I801 SMBus address offsets */
46#define SMBHSTSTS (0 + i801_smba)
47#define SMBHSTCNT (2 + i801_smba)
48#define SMBHSTCMD (3 + i801_smba)
49#define SMBHSTADD (4 + i801_smba)
50#define SMBHSTDAT0 (5 + i801_smba)
51#define SMBHSTDAT1 (6 + i801_smba)
52#define SMBBLKDAT (7 + i801_smba)
53
54/* PCI Address Constants */
55#define SMBBA     0x020
56#define SMBHSTCFG 0x040
57#define SMBREV    0x008
58
59/* Other settings */
60#define MAX_TIMEOUT 500
61#define  ENABLE_INT9 0
62
63/* I801 command constants */
64#define I801_QUICK          0x00
65#define I801_BYTE           0x04
66#define I801_BYTE_DATA      0x08
67#define I801_WORD_DATA      0x0C
68#define I801_BLOCK_DATA     0x14
69#define I801_I2C_BLOCK_DATA 0x18        /* unimplemented */
70#define I801_BLOCK_LAST     0x34
71#define I801_I2C_BLOCK_LAST 0x38        /* unimplemented */
72
73/* insmod parameters */
74
75/* If force is set to anything different from 0, we forcibly enable the
76   I801. DANGEROUS! */
77static int force = 0;
78MODULE_PARM(force,"i");
79MODULE_PARM_DESC(force,"Forcibly enable the I801. DANGEROUS!");
80
81/* If force_addr is set to anything different from 0, we forcibly enable
82   the I801 at the given address. VERY DANGEROUS! */
83static int force_addr = 0;
84MODULE_PARM(force_addr,"i");
85MODULE_PARM_DESC(force_addr,"Forcibly enable the I801 at the given address. "
86                            "EXTREMELY DANGEROUS!");
87
88static int __init i801_cleanup(void);
89static int i801_setup(void);
90static s32 i801_access(struct i2c_adapter *adap, u8 addr, char read_write,
91                        u8 command, int size, union i2c_smbus_data * data);
92static void i801_do_pause( unsigned int amount );
93static int i801_transaction(void);
94static int i801_block_transaction(union i2c_smbus_data *data, char read_write);
95static void i801_inc(struct i2c_adapter *adapter);
96static void i801_dec(struct i2c_adapter *adapter);
97
98#ifdef MODULE
99extern int init_module(void);
100extern int cleanup_module(void);
101#endif /* MODULE */
102
103static struct i2c_algorithm smbus_algorithm = {
104  /* name */            "Non-I2C SMBus adapter",
105  /* id */              I2C_ALGO_SMBUS,
106  /* master_xfer */     NULL,
107  /* smbus_access */    i801_access,
108  /* slave_send */      NULL,
109  /* slave_rcv */       NULL,
110  /* algo_control */    NULL,
111};
112
113static struct i2c_adapter i801_adapter = {
114  "unset",
115  I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
116  &smbus_algorithm,
117  NULL,
118  i801_inc,
119  i801_dec,
120  NULL,
121  NULL,
122};
123
124static int __initdata i801_initialized;
125static unsigned short i801_smba = 0;
126
127
128/* Detect whether a I801 can be found, and initialize it, where necessary.
129   Note the differences between kernels with the old PCI BIOS interface and
130   newer kernels with the real PCI interface. In compat.h some things are
131   defined to make the transition easier. */
132int i801_setup(void)
133{
134  int error_return=0;
135  unsigned char temp;
136
137#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
138  struct pci_dev *I801_dev;
139#else
140  unsigned char I801_bus, I801_devfn;
141  int i,res;
142#endif
143
144  /* First check whether we can access PCI at all */
145  if (pci_present() == 0) {
146    printk("i2c-i801.o: Error: No PCI-bus found!\n");
147    error_return=-ENODEV;
148    goto END;
149  }
150
151  /* Look for the I801, function 3 */
152  /* Have to check for both the 82801AA and 82801AB */
153#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54))
154  /* Note: we keep on searching until we have found 'function 3' */
155  I801_dev = NULL;
156  do
157    I801_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
158                                PCI_DEVICE_ID_INTEL_82801AA_3, I801_dev);
159  while(I801_dev && (PCI_FUNC(I801_dev->devfn) != 3));
160  if(I801_dev == NULL) {
161    do
162      I801_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
163                                  PCI_DEVICE_ID_INTEL_82801AB_3, I801_dev);
164    while(I801_dev && (PCI_FUNC(I801_dev->devfn) != 3));
165  }
166  if(I801_dev == NULL) {
167#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,54) */
168  for (i = 0; 
169       ! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL,
170                                    PCI_DEVICE_ID_INTEL_82801AA_3,
171                                    i,&I801_bus, &I801_devfn)) && 
172         PCI_FUNC(I801_devfn) != 3; 
173       i++);
174  if (res) {
175    for (i = 0; 
176         ! (res = pcibios_find_device(PCI_VENDOR_ID_INTEL,
177                                      PCI_DEVICE_ID_INTEL_82801AB_3,
178                                      i,&I801_bus, &I801_devfn)) && 
179           PCI_FUNC(I801_devfn) != 3; 
180         i++);
181  }
182  if (res) {
183#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,54) */
184    printk("i2c-i801.o: Error: Can't detect I801, function 3!\n");
185    error_return=-ENODEV;
186    goto END;
187  } 
188
189/* Determine the address of the SMBus areas */
190  if (force_addr) {
191    i801_smba = force_addr & 0xfff0;
192    force = 0;
193  } else {
194    pci_read_config_word_united(I801_dev, I801_bus ,I801_devfn,
195                                SMBBA,&i801_smba);
196    i801_smba &= 0xfff0;
197  }
198
199  if (check_region(i801_smba, 8)) {
200    printk("i2c-i801.o: I801_smb region 0x%x already in use!\n", i801_smba);
201    error_return=-ENODEV;
202    goto END;
203  }
204
205  pci_read_config_byte_united(I801_dev, I801_bus, I801_devfn,
206                              SMBHSTCFG, &temp);
207/* If force_addr is set, we program the new address here. Just to make
208   sure, we disable the I801 first. */
209  if (force_addr) {
210    pci_write_config_byte_united(I801_dev, I801_bus, I801_devfn,
211                                SMBHSTCFG, temp & 0xfe);
212    pci_write_config_word_united(I801_dev, I801_bus ,I801_devfn,
213                                 SMBBA,i801_smba);
214    pci_write_config_byte_united(I801_dev, I801_bus, I801_devfn,
215                                SMBHSTCFG, temp | 0x01);
216    printk("i2c-i801.o: WARNING: I801 SMBus interface set to new "
217           "address %04x!\n",i801_smba);
218  } else if ((temp & 1) == 0) {
219    if (force) {
220/* This should never need to be done, but has been noted that
221   many Dell machines have the SMBus interface on the PIIX4
222   disabled!? NOTE: This assumes I/O space and other allocations WERE
223   done by the Bios!  Don't complain if your hardware does weird
224   things after enabling this. :') Check for Bios updates before
225   resorting to this.  */
226      pci_write_config_byte_united(I801_dev, I801_bus, I801_devfn,
227                                       SMBHSTCFG, temp | 1);
228      printk("i2c-i801.o: WARNING: I801 SMBus interface has been FORCEFULLY "
229             "ENABLED!\n");
230    } else {
231      printk("SMBUS: Error: Host SMBus controller not enabled!\n");     
232      error_return=-ENODEV;
233      goto END;
234    }
235  }
236
237  /* note: we assumed that the BIOS picked SMBus or I2C Bus timing
238     appropriately (bit 2 in SMBHSTCFG) */
239  /* Everything is happy, let's grab the memory and set things up. */
240  request_region(i801_smba, 8, "i801-smbus");       
241
242#ifdef DEBUG
243  if (temp & 0x02)
244     printk("i2c-i801.o: I801 using Interrupt SMI# for SMBus.\n");
245  else 
246     printk("i2c-i801.o: I801 using PCI Interrupt for SMBus.\n");
247
248  pci_read_config_byte_united(I801_dev, I801_bus, I801_devfn, SMBREV, 
249                              &temp);
250  printk("i2c-i801.o: SMBREV = 0x%X\n",temp);
251  printk("i2c-i801.o: I801_smba = 0x%X\n",i801_smba);
252#endif /* DEBUG */
253
254END:
255  return error_return;
256}
257
258
259/* Internally used pause function */
260void i801_do_pause( unsigned int amount )
261{
262      current->state = TASK_INTERRUPTIBLE;
263      schedule_timeout(amount);
264}
265
266/* Another internally used function */
267int i801_transaction(void) 
268{
269  int temp;
270  int result=0;
271  int timeout=0;
272
273#ifdef DEBUG
274  printk("i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
275         "DAT1=%02x\n",
276         inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0),
277         inb_p(SMBHSTDAT1));
278#endif
279
280  /* Make sure the SMBus host is ready to start transmitting */
281  /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
282  if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
283#ifdef DEBUG
284    printk("i2c-i801.o: SMBus busy (%02x). Resetting... \n",temp);
285#endif
286    outb_p(temp, SMBHSTSTS);
287    if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
288#ifdef DEBUG
289      printk("i2c-i801.o: Failed! (%02x)\n",temp);
290#endif
291      return -1;
292    } else {
293#ifdef DEBUG
294      printk("i2c-i801.o: Successfull!\n");
295#endif
296    }
297  }
298
299  /* start the transaction by setting bit 6 */
300  outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); 
301
302  /* We will always wait for a fraction of a second! */
303  do {
304    i801_do_pause(1);
305    temp=inb_p(SMBHSTSTS);
306  } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
307
308  /* If the SMBus is still busy, we give up */
309  if (timeout >= MAX_TIMEOUT) {
310#ifdef DEBUG
311    printk("i2c-i801.o: SMBus Timeout!\n"); 
312    result = -1;
313#endif
314  }
315
316  if (temp & 0x10) {
317    result = -1;
318#ifdef DEBUG
319    printk("i2c-i801.o: Error: Failed bus transaction\n");
320#endif
321  }
322
323  if (temp & 0x08) {
324    result = -1;
325    printk("i2c-i801.o: Bus collision! SMBus may be locked until next hard
326           reset. (sorry!)\n");
327    /* Clock stops and slave is stuck in mid-transmission */
328  }
329
330  if (temp & 0x04) {
331    result = -1;
332#ifdef DEBUG
333    printk("i2c-i801.o: Error: no response!\n");
334#endif
335  }
336
337  if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
338    outb_p( inb(SMBHSTSTS), SMBHSTSTS);
339
340  if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
341#ifdef DEBUG
342    printk("i2c-i801.o: Failed reset at end of transaction (%02x)\n",temp);
343#endif
344  }
345#ifdef DEBUG
346  printk("i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
347         "DAT0=%02x, DAT1=%02x\n",
348         inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0),
349         inb_p(SMBHSTDAT1));
350#endif
351  return result;
352}
353
354/* All-inclusive block transaction function */
355int i801_block_transaction(union i2c_smbus_data *data, char read_write)
356{
357  int i, len;
358  int smbcmd;
359  int temp;
360  int result=0;
361  int timeout=0;
362
363  if (read_write == I2C_SMBUS_WRITE) {
364    len = data->block[0];
365    if (len < 1) 
366      len = 1;
367    if (len > 32)
368      len = 32;
369    outb_p(len,SMBHSTDAT0);
370    outb_p(data->block[1],SMBBLKDAT);
371  } else {
372    len = 32;   /* max for reads */
373  }
374
375  for(i = 1; i <= len; i++)
376  {
377    if(i == len  &&  read_write == I2C_SMBUS_READ)
378      smbcmd = I801_BLOCK_LAST;
379    else
380      smbcmd = I801_BLOCK_DATA;
381    if (read_write == I2C_SMBUS_WRITE)
382      outb_p(data->block[i],SMBBLKDAT);
383    outb_p((smbcmd & 0x3C) + (ENABLE_INT9 & 1), SMBHSTCNT);
384
385#ifdef DEBUG
386    printk("i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, "
387           "DAT0=%02x, DAT1=%02x\n",
388           inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0),
389           inb_p(SMBHSTDAT1));
390#endif
391
392  /* Make sure the SMBus host is ready to start transmitting */
393  /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
394  /* 0x9e = Byte_Done, Failed, Bus_Err, Dev_Err, Intr */
395    temp = inb_p(SMBHSTSTS);
396    if (((i == 1)  &&  ((temp & 0x1f) != 0x00)) ||
397        ((i != 1)  &&  ((temp & 0x9e) != 0x00)))
398    {
399#ifdef DEBUG
400      printk("i2c-i801.o: SMBus busy (%02x). Resetting... \n",temp);
401#endif
402      outb_p(temp, SMBHSTSTS);
403      if (((temp = inb_p(SMBHSTSTS)) & 0x9f) != 0x00)
404      {
405        printk("i2c-i801.o: Reset failed! (%02x)\n",temp);
406        return -1;
407      }
408      if(i != 1)
409        return -1;   /* if die in middle of block transaction, fail */
410    }
411
412    /* start the transaction by setting bit 6 */
413    outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT); 
414
415    /* We will always wait for a fraction of a second! */
416    do {
417      i801_do_pause(1);
418      temp=inb_p(SMBHSTSTS);
419    } while ((((i >= len) && (temp & 0x01)) || ((i < len) && (temp & 0x80)))
420             && (timeout++ < MAX_TIMEOUT));
421
422    /* If the SMBus is still busy, we give up */
423    if (timeout >= MAX_TIMEOUT) {
424      result = -1;
425#ifdef DEBUG
426      printk("i2c-i801.o: SMBus Timeout!\n"); 
427#endif
428    }
429
430    if (temp & 0x10) {
431      result = -1;
432#ifdef DEBUG
433      printk("i2c-i801.o: Error: Failed bus transaction\n");
434#endif
435    } else if (temp & 0x08) {
436      result = -1;
437      printk("i2c-i801.o: Bus collision! SMBus may be locked until next hard"
438             " reset. (sorry!)\n");
439      /* Clock stops and slave is stuck in mid-transmission */
440    } else if (temp & 0x04) {
441      result = -1;
442#ifdef DEBUG
443      printk("i2c-i801.o: Error: no response!\n");
444#endif
445    } else if (temp & 0x80) {
446      result = -1;
447#ifdef DEBUG
448      printk("i2c-i801.o: Error: Failed in middle of block!\n");
449#endif
450    }
451
452    if ((temp & 0x9f) != 0x00)
453      outb_p(temp, SMBHSTSTS);
454
455    if ((temp = (0x9f & inb_p(SMBHSTSTS))) != 0x00) {
456#ifdef DEBUG
457      printk("i2c-i801.o: Failed reset at end of transaction (%02x)\n",temp);
458#endif
459    }
460#ifdef DEBUG
461    printk("i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
462           "DAT0=%02x, DAT1=%02x\n",
463           inb_p(SMBHSTCNT),inb_p(SMBHSTCMD),inb_p(SMBHSTADD),inb_p(SMBHSTDAT0),
464           inb_p(SMBHSTDAT1));
465#endif
466
467    if (i == 1  &&  read_write == I2C_SMBUS_READ) {
468        len = inb_p(SMBHSTDAT0);
469      if (len < 1) 
470        len = 1;
471      if (len > 32)
472        len = 32;
473      data->block[0] = len;
474    }
475    if (read_write == I2C_SMBUS_READ)
476      data->block[i] = inb_p(SMBBLKDAT);
477
478    if(result < 0)
479      return(result);
480  }
481  return(0);
482}
483
484/* Return -1 on error. See smbus.h for more information */
485s32 i801_access(struct i2c_adapter *adap, u8 addr, char read_write,
486                 u8 command, int size, union i2c_smbus_data * data)
487{
488
489  switch(size) {
490    case I2C_SMBUS_PROC_CALL:
491      printk("i2c-i801.o: I2C_SMBUS_PROC_CALL not supported!\n");
492      return -1;
493    case I2C_SMBUS_QUICK:
494      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
495      size = I801_QUICK;
496      break;
497    case I2C_SMBUS_BYTE:
498      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
499      if (read_write == I2C_SMBUS_WRITE)
500        outb_p(command, SMBHSTCMD);
501      size = I801_BYTE;
502      break;
503    case I2C_SMBUS_BYTE_DATA:
504      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
505      outb_p(command, SMBHSTCMD);
506      if (read_write == I2C_SMBUS_WRITE)
507        outb_p(data->byte,SMBHSTDAT0);
508      size = I801_BYTE_DATA;
509      break;
510    case I2C_SMBUS_WORD_DATA:
511      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
512      outb_p(command, SMBHSTCMD);
513      if (read_write == I2C_SMBUS_WRITE) {
514        outb_p(data->word & 0xff,SMBHSTDAT0);
515        outb_p((data->word & 0xff00) >> 8,SMBHSTDAT1);
516      }
517      size = I801_WORD_DATA;
518      break;
519    case I2C_SMBUS_BLOCK_DATA:
520      outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD);
521      outb_p(command, SMBHSTCMD);
522      /* Block transactions are very different from piix4 block
523         and from the other i801 transactions. Handle in the
524         i801_block_transaction() routine. */
525      return(i801_block_transaction(data, read_write));
526  }
527
528  /* 'size' is really the transaction type */
529  outb_p((size & 0x3C) + (ENABLE_INT9 & 1), SMBHSTCNT);
530
531  if (i801_transaction()) /* Error in transaction */ 
532    return -1; 
533 
534  if ((read_write == I2C_SMBUS_WRITE) || (size == I801_QUICK))
535    return 0;
536 
537
538  switch(size) {
539    case I801_BYTE: /* Result put in SMBHSTDAT0 */
540      data->byte = inb_p(SMBHSTDAT0);
541      break;
542    case I801_BYTE_DATA:
543      data->byte = inb_p(SMBHSTDAT0);
544      break;
545    case I801_WORD_DATA:
546      data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
547      break;
548  }
549  return 0;
550}
551
552void i801_inc(struct i2c_adapter *adapter)
553{
554        MOD_INC_USE_COUNT;
555}
556
557void i801_dec(struct i2c_adapter *adapter)
558{
559        MOD_DEC_USE_COUNT;
560}
561
562int __init i2c_i801_init(void)
563{
564  int res;
565  printk("i801.o version %s (%s)\n",LM_VERSION,LM_DATE);
566#ifdef DEBUG
567/* PE- It might be good to make this a permanent part of the code! */
568  if (i801_initialized) {
569    printk("i2c-i801.o: Oops, i801_init called a second time!\n");
570    return -EBUSY;
571  }
572#endif
573  i801_initialized = 0;
574  if ((res = i801_setup())) {
575    printk("i2c-i801.o: I801 not detected, module not inserted.\n");
576    i801_cleanup();
577    return res;
578  }
579  i801_initialized ++;
580  sprintf(i801_adapter.name,"SMBus I801 adapter at %04x",i801_smba);
581  if ((res = i2c_add_adapter(&i801_adapter))) {
582    printk("i2c-i801.o: Adapter registration failed, module not inserted.\n");
583    i801_cleanup();
584    return res;
585  }
586  i801_initialized++;
587  printk("i2c-i801.o: I801 bus detected and initialized\n");
588  return 0;
589}
590
591int __init i801_cleanup(void)
592{
593  int res;
594  if (i801_initialized >= 2)
595  {
596    if ((res = i2c_del_adapter(&i801_adapter))) {
597      printk("i2c-i801.o: i2c_del_adapter failed, module not removed\n");
598      return res;
599    } else
600      i801_initialized--;
601  }
602  if (i801_initialized >= 1) {
603    release_region(i801_smba, 8);
604    i801_initialized--;
605  }
606  return 0;
607}
608
609EXPORT_NO_SYMBOLS;
610
611#ifdef MODULE
612
613MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mds@eng.paradyne.com>");
614MODULE_DESCRIPTION("I801 SMBus driver");
615
616int init_module(void)
617{
618  return i2c_i801_init();
619}
620
621int cleanup_module(void)
622{
623  return i801_cleanup();
624}
625
626#endif /* MODULE */
627
Note: See TracBrowser for help on using the browser.