"Fossies" - the Fresh Open Source Software Archive

Member "syslinux-6.03/gpxe/src/drivers/net/3c509.c" (6 Oct 2014, 10755 Bytes) of package /linux/misc/syslinux-6.03.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * Split out into 3c509.c and 3c5x9.c, to make it possible to build a
    3  * 3c529 module without including ISA, ISAPnP and EISA code.
    4  *
    5  */
    6 
    7 FILE_LICENCE ( BSD2 );
    8 
    9 #include <stdint.h>
   10 #include <stdlib.h>
   11 #include <string.h>
   12 #include <errno.h>
   13 #include <gpxe/io.h>
   14 #include <unistd.h>
   15 #include <gpxe/device.h>
   16 #include <gpxe/isa.h>
   17 #include "3c509.h"
   18 
   19 /*
   20  * 3c509 cards have their own method of contention resolution; this
   21  * effectively defines another bus type similar to ISAPnP.  Even the
   22  * original ISA cards can be programatically mapped to any I/O address
   23  * in the range 0x200-0x3e0.
   24  * 
   25  * However, there is a small problem: once you've activated a card,
   26  * the only ways to deactivate it will also wipe its tag, meaning that
   27  * you won't be able to subsequently reactivate it without going
   28  * through the whole ID sequence again.  The solution we adopt is to
   29  * isolate and tag all cards at the start, and to immediately
   30  * re-isolate and re-tag a card after disabling it.
   31  *
   32  */
   33 
   34 static void t509bus_remove ( struct root_device *rootdev );
   35 
   36 static unsigned int t509_id_port = 0;
   37 static unsigned int t509_max_tag = 0;
   38 
   39 /** A 3c509 device */
   40 struct t509_device {
   41     /** Generic device */
   42     struct device dev;
   43     /** Tag */
   44     unsigned int tag;
   45     /** I/O address */
   46     uint16_t ioaddr;
   47     /** Driver-private data
   48      *
   49      * Use t509_set_drvdata() and t509_get_drvdata() to access
   50      * this field.
   51      */
   52     void *priv;
   53 };
   54 
   55 /**
   56  * Set 3c509 driver-private data
   57  *
   58  * @v t509      3c509 device
   59  * @v priv      Private data
   60  */
   61 static inline void t509_set_drvdata ( struct t509_device *t509, void *priv ) {
   62     t509->priv = priv;
   63 }
   64 
   65 /**
   66  * Get 3c509 driver-private data
   67  *
   68  * @v t509      3c509 device
   69  * @ret priv        Private data
   70  */
   71 static inline void * t509_get_drvdata ( struct t509_device *t509 ) {
   72     return t509->priv;
   73 }
   74 
   75 /*
   76  * t509 utility functions
   77  *
   78  */
   79 
   80 static inline void t509_set_id_port ( void ) {
   81     outb ( 0x00, t509_id_port );
   82 }
   83 
   84 static inline void t509_wait_for_id_sequence ( void ) {
   85     outb ( 0x00, t509_id_port );
   86 }
   87 
   88 static inline void t509_global_reset ( void ) {
   89     outb ( 0xc0, t509_id_port );
   90 }
   91 
   92 static inline void t509_reset_tag ( void ) {
   93     outb ( 0xd0, t509_id_port );
   94 }
   95 
   96 static inline void t509_set_tag ( uint8_t tag ) {
   97     outb ( 0xd0 | tag, t509_id_port );
   98 }
   99 
  100 static inline void t509_select_tag ( uint8_t tag ) {
  101     outb ( 0xd8 | tag, t509_id_port );
  102 }
  103 
  104 static inline void t509_activate ( uint16_t ioaddr ) {
  105     outb ( 0xe0 | ( ioaddr >> 4 ), t509_id_port );
  106 }
  107 
  108 static inline void t509_deactivate_and_reset_tag ( uint16_t ioaddr ) {
  109     outb ( GLOBAL_RESET, ioaddr + EP_COMMAND );
  110 }
  111 
  112 static inline void t509_load_eeprom_word ( uint8_t offset ) {
  113     outb ( 0x80 | offset, t509_id_port );
  114 }
  115 
  116 /*
  117  * Find a suitable ID port
  118  *
  119  */
  120 static inline int t509_find_id_port ( void ) {
  121 
  122     for ( t509_id_port = EP_ID_PORT_START ;
  123           t509_id_port < EP_ID_PORT_END ;
  124           t509_id_port += EP_ID_PORT_INC ) {
  125         t509_set_id_port ();
  126         /* See if anything's listening */
  127         outb ( 0xff, t509_id_port );
  128         if ( inb ( t509_id_port ) & 0x01 ) {
  129             /* Found a suitable port */
  130             DBG ( "T509 using ID port at %04x\n", t509_id_port );
  131             return 0;
  132         }
  133     }
  134     /* No id port available */
  135     DBG ( "T509 found no available ID port\n" );
  136     return -ENOENT;
  137 }
  138 
  139 /*
  140  * Send ID sequence to the ID port
  141  *
  142  */
  143 static void t509_send_id_sequence ( void ) {
  144     unsigned short lrs_state, i;
  145 
  146     t509_set_id_port ();
  147     /* Reset IDS on cards */
  148     t509_wait_for_id_sequence ();
  149     lrs_state = 0xff;
  150         for ( i = 0; i < 255; i++ ) {
  151                 outb ( lrs_state, t509_id_port );
  152                 lrs_state <<= 1;
  153                 lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
  154         }
  155 }
  156 
  157 /*
  158  * We get eeprom data from the id_port given an offset into the eeprom.
  159  * Basically; after the ID_sequence is sent to all of the cards; they enter
  160  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
  161  * the eeprom data.  We then read the port 16 times and with every read; the
  162  * cards check for contention (ie: if one card writes a 0 bit and another
  163  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
  164  * compares the data on the bus; if there is a difference then that card goes
  165  * into ID_WAIT state again). In the meantime; one bit of data is returned in
  166  * the AX register which is conveniently returned to us by inb().  Hence; we
  167  * read 16 times getting one bit of data with each read.
  168  */
  169 static uint16_t t509_id_read_eeprom ( int offset ) {
  170     int i, data = 0;
  171 
  172     t509_load_eeprom_word ( offset );
  173     /* Do we really need this wait? Won't be noticeable anyway */
  174     udelay(10000);
  175 
  176     for ( i = 0; i < 16; i++ ) {
  177         data = ( data << 1 ) | ( inw ( t509_id_port ) & 1 );
  178     }
  179     return data;
  180 }
  181 
  182 /*
  183  * Isolate and tag all t509 cards
  184  *
  185  */
  186 static int t509_isolate ( void ) {
  187     unsigned int i;
  188     uint16_t contend[3];
  189     int rc;
  190 
  191     /* Find a suitable ID port */
  192     if ( ( rc = t509_find_id_port() ) != 0 )
  193         return rc;
  194 
  195     while ( 1 ) {
  196 
  197         /* All cards are in ID_WAIT state each time we go
  198          * through this loop.
  199          */
  200 
  201         /* Send the ID sequence */
  202         t509_send_id_sequence();
  203 
  204         /* First time through, reset all tags.  On subsequent
  205          * iterations, kill off any already-tagged cards
  206          */
  207         if ( t509_max_tag == 0 ) {
  208             t509_reset_tag();
  209         } else {
  210             t509_select_tag ( 0 );
  211         }
  212     
  213         /* Read the manufacturer ID, to see if there are any
  214          * more cards
  215          */
  216         if ( t509_id_read_eeprom ( EEPROM_MFG_ID ) != MFG_ID ) {
  217             DBG ( "T509 saw %s signs of life\n",
  218                   t509_max_tag ? "no further" : "no" );
  219             break;
  220         }
  221 
  222         /* Perform contention selection on the MAC address */
  223         for ( i = 0 ; i < 3 ; i++ ) {
  224             contend[i] = t509_id_read_eeprom ( i );
  225         }
  226 
  227         /* Only one device will still be left alive.  Tag it. */
  228         ++t509_max_tag;
  229         DBG ( "T509 found card %04x%04x%04x, assigning tag %02x\n",
  230               contend[0], contend[1], contend[2], t509_max_tag );
  231         t509_set_tag ( t509_max_tag );
  232 
  233         /* Return all cards back to ID_WAIT state */
  234         t509_wait_for_id_sequence();
  235     }
  236 
  237     DBG ( "T509 found %d cards using ID port %04x\n",
  238           t509_max_tag, t509_id_port );
  239     return 0;
  240 }
  241 
  242 /*
  243  * Activate a T509 device
  244  *
  245  * The device will be enabled at whatever ioaddr is specified in the
  246  * struct t509_device; there is no need to stick with the default
  247  * ioaddr read from the EEPROM.
  248  *
  249  */
  250 static inline void activate_t509_device ( struct t509_device *t509 ) {
  251     t509_send_id_sequence ();
  252     t509_select_tag ( t509->tag );
  253     t509_activate ( t509->ioaddr );
  254     DBG ( "T509 activated device %02x at ioaddr %04x\n",
  255           t509->tag, t509->ioaddr );
  256 }
  257 
  258 /*
  259  * Deactivate a T509 device
  260  *
  261  * Disabling also clears the tag, so we immediately isolate and re-tag
  262  * this card.
  263  *
  264  */
  265 static inline void deactivate_t509_device ( struct t509_device *t509 ) {
  266     t509_deactivate_and_reset_tag ( t509->ioaddr );
  267     udelay ( 1000 );
  268     t509_send_id_sequence ();
  269     t509_select_tag ( 0 );
  270     t509_set_tag ( t509->tag );
  271     t509_wait_for_id_sequence ();
  272     DBG ( "T509 deactivated device at %04x and re-tagged as %02x\n",
  273           t509->ioaddr, t509->tag );
  274 }
  275 
  276 /*
  277  * The ISA probe function
  278  *
  279  */
  280 static int legacy_t509_probe ( struct nic *nic, void *hwdev ) {
  281     struct t509_device *t509 = hwdev;
  282 
  283     /* We could change t509->ioaddr if we wanted to */
  284     activate_t509_device ( t509 );
  285     nic->ioaddr = t509->ioaddr;
  286 
  287     /* Hand off to generic t5x9 probe routine */
  288     return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
  289 }
  290 
  291 static void legacy_t509_disable ( struct nic *nic, void *hwdev ) {
  292     struct t509_device *t509 = hwdev;
  293 
  294     t5x9_disable ( nic );
  295     deactivate_t509_device ( t509 );
  296 }
  297 
  298 static inline void legacy_t509_set_drvdata ( void *hwdev, void *priv ) {
  299     t509_set_drvdata ( hwdev, priv );
  300 }
  301 
  302 static inline void * legacy_t509_get_drvdata ( void *hwdev ) {
  303     return t509_get_drvdata ( hwdev );
  304 }
  305 
  306 /**
  307  * Probe a 3c509 device
  308  *
  309  * @v t509      3c509 device
  310  * @ret rc      Return status code
  311  *
  312  * Searches for a driver for the 3c509 device.  If a driver is found,
  313  * its probe() routine is called.
  314  */
  315 static int t509_probe ( struct t509_device *t509 ) {
  316     DBG ( "Adding 3c509 device %02x (I/O %04x)\n",
  317           t509->tag, t509->ioaddr );
  318     return legacy_probe ( t509, legacy_t509_set_drvdata, &t509->dev,
  319                   legacy_t509_probe, legacy_t509_disable );
  320 }
  321 
  322 /**
  323  * Remove a 3c509 device
  324  *
  325  * @v t509      3c509 device
  326  */
  327 static void t509_remove ( struct t509_device *t509 ) {
  328     legacy_remove ( t509, legacy_t509_get_drvdata, legacy_t509_disable );
  329     DBG ( "Removed 3c509 device %02x\n", t509->tag );
  330 }
  331 
  332 /**
  333  * Probe 3c509 root bus
  334  *
  335  * @v rootdev       3c509 bus root device
  336  *
  337  * Scans the 3c509 bus for devices and registers all devices it can
  338  * find.
  339  */
  340 static int t509bus_probe ( struct root_device *rootdev ) {
  341     struct t509_device *t509 = NULL;
  342     unsigned int tag;
  343     unsigned int iobase;
  344     int rc;
  345 
  346     /* Perform isolation and tagging */
  347     if ( ( rc = t509_isolate() ) != 0 )
  348         return rc;
  349 
  350     for ( tag = 1 ; tag <= t509_max_tag ; tag++ ) {
  351         /* Allocate struct t509_device */
  352         if ( ! t509 )
  353             t509 = malloc ( sizeof ( *t509 ) );
  354         if ( ! t509 ) {
  355             rc = -ENOMEM;
  356             goto err;
  357         }
  358         memset ( t509, 0, sizeof ( *t509 ) );
  359         t509->tag = tag;
  360 
  361         /* Send the ID sequence */
  362         t509_send_id_sequence ();
  363 
  364         /* Select the specified tag */
  365         t509_select_tag ( t509->tag );
  366 
  367         /* Read the default I/O address */
  368         iobase = t509_id_read_eeprom ( EEPROM_ADDR_CFG );
  369         t509->ioaddr = 0x200 + ( ( iobase & 0x1f ) << 4 );
  370 
  371         /* Send card back to ID_WAIT */
  372         t509_wait_for_id_sequence();
  373 
  374         /* Add to device hierarchy */
  375         snprintf ( t509->dev.name, sizeof ( t509->dev.name ),
  376                "t509%02x", tag );
  377         t509->dev.desc.bus_type = BUS_TYPE_ISA;
  378         t509->dev.desc.vendor = MFG_ID;
  379         t509->dev.desc.device = PROD_ID;
  380         t509->dev.parent = &rootdev->dev;
  381         list_add ( &t509->dev.siblings, &rootdev->dev.children );
  382         INIT_LIST_HEAD ( &t509->dev.children );
  383             
  384         /* Look for a driver */
  385         if ( t509_probe ( t509 ) == 0 ) {
  386             /* t509dev registered, we can drop our ref */
  387             t509 = NULL;
  388         } else {
  389             /* Not registered; re-use struct */
  390             list_del ( &t509->dev.siblings );
  391         }
  392     }
  393 
  394     free ( t509 );
  395     return 0;
  396 
  397  err:
  398     free ( t509 );
  399     t509bus_remove ( rootdev );
  400     return rc;
  401 }
  402 
  403 /**
  404  * Remove 3c509 root bus
  405  *
  406  * @v rootdev       3c509 bus root device
  407  */
  408 static void t509bus_remove ( struct root_device *rootdev ) {
  409     struct t509_device *t509;
  410     struct t509_device *tmp;
  411 
  412     list_for_each_entry_safe ( t509, tmp, &rootdev->dev.children,
  413                    dev.siblings ) {
  414         t509_remove ( t509 );
  415         list_del ( &t509->dev.siblings );
  416         free ( t509 );
  417     }
  418 }
  419 
  420 /** 3c509 bus root device driver */
  421 static struct root_driver t509_root_driver = {
  422     .probe = t509bus_probe,
  423     .remove = t509bus_remove,
  424 };
  425 
  426 /** 3c509 bus root device */
  427 struct root_device t509_root_device __root_device = {
  428     .dev = { .name = "3c509" },
  429     .driver = &t509_root_driver,
  430 };
  431 
  432 ISA_ROM ( "3c509", "3c509" );