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

Revision 537, 18.2 KB (checked in by mds, 14 years ago)

(mds) Added block read/write support. Much different than piix4.

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