Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/hw/netif/dp8390/ne2000.c

    r7e752b2 r7922dea  
    11/*
    2  * Copyright (c) 1987,1997, 2006, Vrije Universiteit, Amsterdam, The Netherlands All rights reserved. Redistribution and use of the MINIX 3 operating system in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
    3  *
    4  * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    5  * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    6  * * Neither the name of the Vrije Universiteit nor the names of the software authors or contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    7  * * Any deviations from these conditions require written permission from the copyright holder in advance
    8  *
    9  *
    10  * Disclaimer
    11  *
    12  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
     2 * Copyright (c) 2009 Lukas Mejdrech
     3 * Copyright (c) 2011 Martin Decky
     4 * All rights reserved.
     5 *
     6 * Redistribution and use in source and binary forms, with or without
     7 * modification, are permitted provided that the following conditions
     8 * are met:
     9 *
     10 * - Redistributions of source code must retain the above copyright
     11 *   notice, this list of conditions and the following disclaimer.
     12 * - Redistributions in binary form must reproduce the above copyright
     13 *   notice, this list of conditions and the following disclaimer in the
     14 *   documentation and/or other materials provided with the distribution.
     15 * - The name of the author may not be used to endorse or promote products
     16 *   derived from this software without specific prior written permission.
     17 *
     18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1319 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    1420 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    15  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ANY AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    1622 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    1723 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     
    2026 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    2127 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    22  *
    23  * Changes:
    24  *  2009 ported to HelenOS, Lukas Mejdrech
     28 */
     29
     30/*
     31 * This code is based upon the NE2000 driver for MINIX,
     32 * distributed according to a BSD-style license.
     33 *
     34 * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
     35 * Copyright (c) 1992, 1994 Philip Homburg
     36 * Copyright (c) 1996 G. Falzoni
     37 *
    2538 */
    2639
     
    3548#include <stdio.h>
    3649#include <unistd.h>
    37 
    3850#include "dp8390_port.h"
    39 
    40 /*
    41 ne2000.c
    42 
    43 Driver for the ne2000 ethernet cards. This file contains only the ne2000
    44 specific code, the rest is in dp8390.c
    45 
    46 Created:        March 15, 1994 by Philip Homburg <philip@f-mnx.phicoh.com>
    47 */
    48 
    49 //#include "../drivers.h"
    50 
    51 //#include <net/gen/ether.h>
    52 //#include <net/gen/eth_io.h>
    53 //#if __minix_vmd
    54 //#include "config.h"
    55 //#endif
    56 
    57 #include "local.h"
    5851#include "dp8390.h"
    5952#include "ne2000.h"
    6053
    61 #if ENABLE_NE2000
    62 
    63 /** Number of bytes to transfer.
    64  */
    65 #define N 100
    66 
    67 //#define MILLIS_TO_TICKS(m)  (((m)*HZ/1000)+1)
    68 
    69 /** Sleeps for the defined millicesonds.
    70  *  @param[in] millis The number of milliseconds to sleep.
    71  */
    72 #define milli_delay(millis)     usleep((millis) * 1000)
    73 
    74 /** Type definition of the testing function.
    75  */
    76 _PROTOTYPE(typedef int (*testf_t), (dpeth_t *dep, int pos, u8_t *pat)   );
    77 
    78 /** First data pattern.
    79  */
    80 u8_t    pat0[]= {0x00, 0x00, 0x00, 0x00};
    81 
    82 /** Second data pattern.
    83  */
    84 u8_t    pat1[]= {0xFF, 0xFF, 0xFF, 0xFF};
    85 
    86 /** Third data pattern.
    87  */
    88 u8_t    pat2[]= {0xA5, 0x5A, 0x69, 0x96};
    89 
    90 /** Fourth data pattern.
    91  */
    92 u8_t    pat3[]= {0x96, 0x69, 0x5A, 0xA5};
     54/** Number of bytes to transfer */
     55#define N  100
     56
     57typedef int (*testf_t)(dpeth_t *dep, int pos, uint8_t *pat);
     58
     59/** Data patterns */
     60uint8_t pat0[] = {0x00, 0x00, 0x00, 0x00};
     61uint8_t pat1[] = {0xFF, 0xFF, 0xFF, 0xFF};
     62uint8_t pat2[] = {0xA5, 0x5A, 0x69, 0x96};
     63uint8_t pat3[] = {0x96, 0x69, 0x5A, 0xA5};
    9364
    9465/** Tests 8 bit NE2000 network interface.
     
    9768 *  @param[in] pat The data pattern to be written.
    9869 *  @returns True on success.
    99  *  @returns FALSE otherwise.
    100  */
    101 static int test_8(dpeth_t *dep, int pos, u8_t *pat);
     70 *  @returns false otherwise.
     71 */
     72static int test_8(dpeth_t *dep, int pos, uint8_t *pat);
    10273
    10374/** Tests 16 bit NE2000 network interface.
     
    10677 *  @param[in] pat The data pattern to be written.
    10778 *  @returns True on success.
    108  *  @returns FALSE otherwise.
    109  */
    110 static int test_16(dpeth_t *dep, int pos, u8_t *pat);
    111 
    112 /** Stops the NE2000 network interface.
    113  *  @param[in,out] dep The network interface structure.
    114  */
    115 static void ne_stop(dpeth_t *dep);
    116 //_PROTOTYPE(static void milli_delay, (unsigned long millis)            );
    117 
    118 /** Initializes the NE2000 network interface.
    119  *  @param[in,out] dep The network interface structure.
    120  */
    121 void ne_init(struct dpeth *dep);
    122 
    123 /*===========================================================================*
    124  *                              ne_probe                                     *
    125  *===========================================================================*/
    126 int ne_probe(dep)
    127 dpeth_t *dep;
     79 *  @returns false otherwise.
     80 */
     81static int test_16(dpeth_t *dep, int pos, uint8_t *pat);
     82
     83int ne_probe(dpeth_t *dep)
    12884{
    12985        int byte;
     
    13187        int loc1, loc2;
    13288        testf_t f;
    133 
    134         dep->de_dp8390_port= dep->de_base_port + NE_DP8390;
    135 
    136         /* We probe for an ne1000 or an ne2000 by testing whether the
     89       
     90        dep->de_dp8390_port = dep->de_base_port + NE_DP8390;
     91       
     92        /*
     93         * We probe for an ne1000 or an ne2000 by testing whether the
    13794         * on board is reachable through the dp8390. Note that the
    13895         * ne1000 is an 8bit card and has a memory region distict from
    13996         * the 16bit ne2000
    14097         */
    141 
    142         for (dep->de_16bit= 0; dep->de_16bit < 2; dep->de_16bit++)
    143         {
     98       
     99        for (dep->de_16bit = 0; dep->de_16bit < 2; dep->de_16bit++) {
    144100                /* Reset the ethernet card */
    145101                byte= inb_ne(dep, NE_RESET);
    146                 milli_delay(2);
     102                usleep(2000);
    147103                outb_ne(dep, NE_RESET, byte);
    148                 milli_delay(2);
    149 
     104                usleep(2000);
     105               
    150106                /* Reset the dp8390 */
    151107                outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
    152                 for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) &ISR_RST) == 0); i++)
     108                for (i = 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
    153109                        ; /* Do nothing */
    154 
     110               
    155111                /* Check if the dp8390 is really there */
    156                 if ((inb_reg0(dep, DP_CR) &(CR_STP|CR_DM_ABORT)) !=
    157                         (CR_STP|CR_DM_ABORT))
    158                 {
     112                if ((inb_reg0(dep, DP_CR) & (CR_STP | CR_DM_ABORT)) !=
     113                    (CR_STP | CR_DM_ABORT))
    159114                        return 0;
    160                 }
    161 
     115               
    162116                /* Disable the receiver and init TCR and DCR. */
    163117                outb_reg0(dep, DP_RCR, RCR_MON);
    164118                outb_reg0(dep, DP_TCR, TCR_NORMAL);
    165                 if (dep->de_16bit)
    166                 {
     119                if (dep->de_16bit) {
    167120                        outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES |
    168                                 DCR_BMS);
     121                            DCR_BMS);
     122                } else {
     123                        outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
     124                            DCR_BMS);
    169125                }
    170                 else
    171                 {
    172                         outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES |
    173                                 DCR_BMS);
     126               
     127                if (dep->de_16bit) {
     128                        loc1 = NE2000_START;
     129                        loc2 = NE2000_START + NE2000_SIZE - 4;
     130                        f = test_16;
     131                } else {
     132                        loc1 = NE1000_START;
     133                        loc2 = NE1000_START + NE1000_SIZE - 4;
     134                        f = test_8;
    174135                }
    175 
    176                 if (dep->de_16bit)
    177                 {
    178                         loc1= NE2000_START;
    179                         loc2= NE2000_START + NE2000_SIZE - 4;
    180                         f= test_16;
    181                 }
    182                 else
    183                 {
    184                         loc1= NE1000_START;
    185                         loc2= NE1000_START + NE1000_SIZE - 4;
    186                         f= test_8;
    187                 }
    188                 if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
    189                         f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
    190                         f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
    191                         f(dep, loc2, pat2) && f(dep, loc2, pat3))
    192                 {
    193                         /* We don't need a memory segment */
    194                         dep->de_linmem= 0;
    195                         if (!dep->de_pci)
    196                                 dep->de_initf= ne_init;
    197                         dep->de_stopf= ne_stop;
    198                         dep->de_prog_IO= 1;
     136               
     137                if (f(dep, loc1, pat0) && f(dep, loc1, pat1) &&
     138                    f(dep, loc1, pat2) && f(dep, loc1, pat3) &&
     139                    f(dep, loc2, pat0) && f(dep, loc2, pat1) &&
     140                    f(dep, loc2, pat2) && f(dep, loc2, pat3)) {
    199141                        return 1;
    200142                }
    201143        }
     144       
    202145        return 0;
    203146}
    204147
    205 /*===========================================================================*
    206  *                              ne_init                                      *
    207  *===========================================================================*/
    208 void ne_init(dep)
    209 dpeth_t *dep;
     148/** Initializes the NE2000 network interface.
     149 *
     150 *  @param[in,out] dep The network interface structure.
     151 *
     152 */
     153void ne_init(dpeth_t *dep)
    210154{
    211155        int i;
    212156        int word, sendq_nr;
    213 
     157       
    214158        /* Setup a transfer to get the ethernet address. */
    215159        if (dep->de_16bit)
     
    217161        else
    218162                outb_reg0(dep, DP_RBCR0, 6);
     163       
    219164        outb_reg0(dep, DP_RBCR1, 0);
    220165        outb_reg0(dep, DP_RSAR0, 0);
    221166        outb_reg0(dep, DP_RSAR1, 0);
    222167        outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    223 
    224         for (i= 0; i<6; i++)
    225         {
    226                 if (dep->de_16bit)
    227                 {
    228                         word= inw_ne(dep, NE_DATA);
    229                         dep->de_address.ea_addr[i]= word;
    230                 }
    231                 else
    232                 {
     168       
     169        for (i = 0; i < 6; i++) {
     170                if (dep->de_16bit) {
     171                        word = inw_ne(dep, NE_DATA);
     172                        dep->de_address.ea_addr[i] = word;
     173                } else
    233174                        dep->de_address.ea_addr[i] = inb_ne(dep, NE_DATA);
    234                 }
    235         }
     175        }
     176       
    236177        dep->de_data_port= dep->de_base_port + NE_DATA;
    237         if (dep->de_16bit)
    238         {
    239                 dep->de_ramsize= NE2000_SIZE;
    240                 dep->de_offset_page= NE2000_START / DP_PAGESIZE;
    241         }
    242         else
    243         {
    244                 dep->de_ramsize= NE1000_SIZE;
    245                 dep->de_offset_page= NE1000_START / DP_PAGESIZE;
    246         }
    247 
     178        if (dep->de_16bit) {
     179                dep->de_ramsize = NE2000_SIZE;
     180                dep->de_offset_page = NE2000_START / DP_PAGESIZE;
     181        } else {
     182                dep->de_ramsize = NE1000_SIZE;
     183                dep->de_offset_page = NE1000_START / DP_PAGESIZE;
     184        }
     185       
    248186        /* Allocate one send buffer (1.5KB) per 8KB of on board memory. */
    249         sendq_nr= dep->de_ramsize / 0x2000;
     187        sendq_nr = dep->de_ramsize / 0x2000;
     188       
    250189        if (sendq_nr < 1)
    251                 sendq_nr= 1;
     190                sendq_nr = 1;
    252191        else if (sendq_nr > SENDQ_NR)
    253                 sendq_nr= SENDQ_NR;
    254         dep->de_sendq_nr= sendq_nr;
    255         for (i= 0; i<sendq_nr; i++)
    256         {
    257                 dep->de_sendq[i].sq_sendpage= dep->de_offset_page +
    258                         i*SENDQ_PAGES; 
    259         }
    260 
    261         dep->de_startpage= dep->de_offset_page + i*SENDQ_PAGES;
    262         dep->de_stoppage= dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
    263 
    264         /* Can't override the default IRQ. */
    265         dep->de_irq &= ~DEI_DEFAULT;
    266 
    267         if (!debug)
    268         {
    269                 printf("%s: NE%d000 at %#lx:%d\n",
    270                     dep->de_name, dep->de_16bit ? 2 : 1,
    271                     dep->de_base_port, dep->de_irq);
    272         }
    273         else
    274         {
    275                 printf("%s: Novell NE%d000 ethernet card at I/O address "
    276                     "%#lx, memory size %#lx, irq %d\n",
    277                     dep->de_name, dep->de_16bit ? 2 : 1,
    278                     dep->de_base_port, dep->de_ramsize, dep->de_irq);
    279         }
    280 }
    281 
    282 /*===========================================================================*
    283  *                              test_8                                       *
    284  *===========================================================================*/
    285 static int test_8(dep, pos, pat)
    286 dpeth_t *dep;
    287 int pos;
    288 u8_t *pat;
    289 {
    290         u8_t buf[4];
    291         int i;
    292         int r;
    293 
    294         outb_reg0(dep, DP_ISR, 0xFF);
    295 
     192                sendq_nr = SENDQ_NR;
     193       
     194        dep->de_sendq_nr = sendq_nr;
     195        for (i = 0; i < sendq_nr; i++)
     196                dep->de_sendq[i].sq_sendpage = dep->de_offset_page + i * SENDQ_PAGES;
     197       
     198        dep->de_startpage = dep->de_offset_page + i * SENDQ_PAGES;
     199        dep->de_stoppage = dep->de_offset_page + dep->de_ramsize / DP_PAGESIZE;
     200       
     201        printf("Novell NE%d000 ethernet card at I/O address "
     202            "%#lx, memory size %#lx, irq %d\n",
     203            dep->de_16bit ? 2 : 1, dep->de_base_port, dep->de_ramsize,
     204            dep->de_irq);
     205}
     206
     207static int test_8(dpeth_t *dep, int pos, uint8_t *pat)
     208{
     209        uint8_t buf[4];
     210        int i;
     211       
     212        outb_reg0(dep, DP_ISR, 0xff);
     213       
    296214        /* Setup a transfer to put the pattern. */
    297215        outb_reg0(dep, DP_RBCR0, 4);
    298216        outb_reg0(dep, DP_RBCR1, 0);
    299         outb_reg0(dep, DP_RSAR0, pos &0xFF);
     217        outb_reg0(dep, DP_RSAR0, pos & 0xff);
    300218        outb_reg0(dep, DP_RSAR1, pos >> 8);
    301219        outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
    302 
    303         for (i= 0; i<4; i++)
     220       
     221        for (i = 0; i < 4; i++)
    304222                outb_ne(dep, NE_DATA, pat[i]);
    305 
    306         for (i= 0; i<N; i++)
    307         {
     223       
     224        for (i = 0; i < N; i++) {
     225                if (inb_reg0(dep, DP_ISR) & ISR_RDC)
     226                        break;
     227        }
     228       
     229        if (i == N) {
     230                printf("NE1000 remote DMA test failed\n");
     231                return 0;
     232        }
     233       
     234        outb_reg0(dep, DP_RBCR0, 4);
     235        outb_reg0(dep, DP_RBCR1, 0);
     236        outb_reg0(dep, DP_RSAR0, pos & 0xff);
     237        outb_reg0(dep, DP_RSAR1, pos >> 8);
     238        outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
     239       
     240        for (i = 0; i < 4; i++)
     241                buf[i] = inb_ne(dep, NE_DATA);
     242       
     243        return (memcmp(buf, pat, 4) == 0);
     244}
     245
     246static int test_16(dpeth_t *dep, int pos, uint8_t *pat)
     247{
     248        uint8_t buf[4];
     249        int i;
     250       
     251        outb_reg0(dep, DP_ISR, 0xff);
     252       
     253        /* Setup a transfer to put the pattern. */
     254        outb_reg0(dep, DP_RBCR0, 4);
     255        outb_reg0(dep, DP_RBCR1, 0);
     256        outb_reg0(dep, DP_RSAR0, pos & 0xff);
     257        outb_reg0(dep, DP_RSAR1, pos >> 8);
     258        outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
     259       
     260        for (i = 0; i < 4; i += 2)
     261                outw_ne(dep, NE_DATA, *(uint16_t *)(pat + i));
     262       
     263        for (i = 0; i < N; i++) {
    308264                if (inb_reg0(dep, DP_ISR) &ISR_RDC)
    309265                        break;
    310266        }
    311         if (i == N)
    312         {
    313                 if (debug)
    314                 {
    315                         printf("%s: NE1000 remote DMA test failed\n",
    316                                 dep->de_name);
    317                 }
     267       
     268        if (i == N) {
     269                printf("NE2000 remote DMA test failed\n");
    318270                return 0;
    319271        }
    320 
    321         outb_reg0(dep, DP_RBCR0, 4);
    322         outb_reg0(dep, DP_RBCR1, 0);
    323         outb_reg0(dep, DP_RSAR0, pos &0xFF);
     272       
     273        outb_reg0(dep, DP_RBCR0, 4);
     274        outb_reg0(dep, DP_RBCR1, 0);
     275        outb_reg0(dep, DP_RSAR0, pos & 0xff);
    324276        outb_reg0(dep, DP_RSAR1, pos >> 8);
    325277        outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    326 
    327         for (i= 0; i<4; i++)
    328                 buf[i]= inb_ne(dep, NE_DATA);
    329 
    330         r= (memcmp(buf, pat, 4) == 0);
    331         return r;
    332 }
    333 
    334 /*===========================================================================*
    335  *                              test_16                                      *
    336  *===========================================================================*/
    337 static int test_16(dep, pos, pat)
    338 dpeth_t *dep;
    339 int pos;
    340 u8_t *pat;
    341 {
    342         u8_t buf[4];
    343         int i;
    344         int r;
    345 
    346         outb_reg0(dep, DP_ISR, 0xFF);
    347 
    348         /* Setup a transfer to put the pattern. */
    349         outb_reg0(dep, DP_RBCR0, 4);
    350         outb_reg0(dep, DP_RBCR1, 0);
    351         outb_reg0(dep, DP_RSAR0, pos &0xFF);
    352         outb_reg0(dep, DP_RSAR1, pos >> 8);
    353         outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
    354 
    355         for (i= 0; i<4; i += 2)
    356         {
    357                 outw_ne(dep, NE_DATA, *(u16_t *)(pat+i));
    358         }
    359 
    360         for (i= 0; i<N; i++)
    361         {
    362                 if (inb_reg0(dep, DP_ISR) &ISR_RDC)
    363                         break;
    364         }
    365         if (i == N)
    366         {
    367                 if (debug)
    368                 {
    369                         printf("%s: NE2000 remote DMA test failed\n",
    370                                 dep->de_name);
    371                 }
    372                 return 0;
    373         }
    374 
    375         outb_reg0(dep, DP_RBCR0, 4);
    376         outb_reg0(dep, DP_RBCR1, 0);
    377         outb_reg0(dep, DP_RSAR0, pos &0xFF);
    378         outb_reg0(dep, DP_RSAR1, pos >> 8);
    379         outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
    380 
    381         for (i= 0; i<4; i += 2)
    382         {
    383                 *(u16_t *)(buf+i)= inw_ne(dep, NE_DATA);
    384         }
    385 
    386         r= (memcmp(buf, pat, 4) == 0);
    387         return r;
    388 }
    389 
    390 /*===========================================================================*
    391  *                              ne_stop                                      *
    392  *===========================================================================*/
    393 static void ne_stop(dep)
    394 dpeth_t *dep;
    395 {
    396         int byte;
    397 
     278       
     279        for (i = 0; i < 4; i += 2)
     280                *(uint16_t *)(buf + i) = inw_ne(dep, NE_DATA);
     281       
     282        return (memcmp(buf, pat, 4) == 0);
     283}
     284
     285/** Stop the NE2000 network interface.
     286 *
     287 *  @param[in,out] dep The network interface structure.
     288 *
     289 */
     290void ne_stop(dpeth_t *dep)
     291{
    398292        /* Reset the ethernet card */
    399         byte= inb_ne(dep, NE_RESET);
    400         milli_delay(2);
     293        int byte = inb_ne(dep, NE_RESET);
     294        usleep(2000);
    401295        outb_ne(dep, NE_RESET, byte);
    402296}
    403 /*
    404 static void milli_delay(unsigned long millis)
    405 {
    406         tickdelay(MILLIS_TO_TICKS(millis));
    407 }
    408 */
    409 #endif /* ENABLE_NE2000 */
    410 
    411 /*
    412  * $PchId: ne2000.c,v 1.10 2004/08/03 12:03:00 philip Exp $
    413  */
    414297
    415298/** @}
Note: See TracChangeset for help on using the changeset viewer.