name should be const
[people/lynusvaz/gpxe.git] / src / drivers / net / 3c509.c
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 #include "eisa.h"
8 #include "isa.h"
9 #include "io.h"
10 #include "timer.h"
11 #include "string.h"
12 #include "etherboot.h"
13 #include "3c509.h"
14
15 /*
16  * 3c509 cards have their own method of contention resolution; this
17  * effectively defines another bus type.
18  *
19  */
20
21 /*
22  * A physical t509 device
23  *
24  */
25 struct t509_device {
26         char *magic; /* must be first */
27         uint16_t id_port;
28         uint16_t ioaddr;
29         unsigned char current_tag;
30 };
31
32 /*
33  * A t509 driver
34  *
35  */
36 struct t509_driver {
37         const char *name;
38 };
39
40 /*
41  * Ensure that there is sufficient space in the shared dev_bus
42  * structure for a struct pci_device.
43  *
44  */
45 DEV_BUS( struct t509_device, t509_dev );
46 static char t509_magic[0]; /* guaranteed unique symbol */
47
48 /*
49  * Find a port that can be used for contention select
50  *
51  * Called only once, so inlined for efficiency.
52  *
53  */
54 static inline int find_id_port ( struct t509_device *t509 ) {
55         for ( t509->id_port = EP_ID_PORT_START ;
56               t509->id_port < EP_ID_PORT_END ;
57               t509->id_port += EP_ID_PORT_INC ) {
58                 outb ( 0x00, t509->id_port );
59                 outb ( 0xff, t509->id_port );
60                 if ( inb ( t509->id_port ) & 0x01 ) {
61                         /* Found a suitable port */
62                         return 1;
63                 }
64         }
65         /* No id port available */
66         return 0;
67 }
68
69 /*
70  * Send ID sequence to the ID port
71  *
72  * Called only once, so inlined for efficiency.
73  *
74  */
75 static inline void send_id_sequence ( struct t509_device *t509 ) {
76         unsigned short lrs_state, i;
77
78         outb ( 0x00, t509->id_port );
79         outb ( 0x00, t509->id_port );
80         lrs_state = 0xff;
81         for ( i = 0; i < 255; i++ ) {
82                 outb ( lrs_state, t509->id_port );
83                 lrs_state <<= 1;
84                 lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state;
85         }
86 }
87
88 /*
89  * We get eeprom data from the id_port given an offset into the eeprom.
90  * Basically; after the ID_sequence is sent to all of the cards; they enter
91  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
92  * the eeprom data.  We then read the port 16 times and with every read; the
93  * cards check for contention (ie: if one card writes a 0 bit and another
94  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
95  * compares the data on the bus; if there is a difference then that card goes
96  * into ID_WAIT state again). In the meantime; one bit of data is returned in
97  * the AX register which is conveniently returned to us by inb().  Hence; we
98  * read 16 times getting one bit of data with each read.
99  */
100 static uint16_t id_read_eeprom ( struct t509_device *t509, int offset ) {
101         int i, data = 0;
102
103         outb ( 0x80 + offset, t509->id_port );
104         /* Do we really need this wait? Won't be noticeable anyway */
105         udelay(10000);
106
107         for ( i = 0; i < 16; i++ ) {
108                 data = ( data << 1 ) | ( inw ( t509->id_port ) & 1 );
109         }
110         return data;
111 }
112
113 /*
114  * Find the next t509 device
115  *
116  * Called only once, so inlined for efficiency.
117  *
118  */
119 static inline int fill_t509_device ( struct t509_device *t509 ) {
120         int i;
121         uint16_t iobase;
122
123         /* 
124          * If this is the start of the scan, clear all tag registers.
125          * Otherwise, tell already-found NICs not to respond.
126          *
127          */
128         if ( t509->current_tag == 0 ) {
129                 outb ( 0xd0, t509->id_port );
130         } else {
131                 outb ( 0xd8, t509->id_port ) ;
132         }
133
134         /* Send the ID sequence */
135         send_id_sequence ( t509 );
136
137         /* Check the manufacturer ID */
138         if ( id_read_eeprom ( t509, EEPROM_MFG_ID ) != MFG_ID ) {
139                 /* No more t509 devices */
140                 return 0;
141         }
142
143         /* Do contention select by reading the MAC address */
144         for ( i = 0 ; i < 3 ; i++ ) {
145                 id_read_eeprom ( t509, i );
146         }
147
148         /* By now, only one device will be left active.  Get its I/O
149          * address, tag and activate the adaptor.  Tagging will
150          * prevent it taking part in the next scan, enabling us to see
151          * the next device.
152          */
153         iobase = id_read_eeprom ( t509, EEPROM_ADDR_CFG );
154         t509->ioaddr = 0x200 + ( ( iobase & 0x1f ) << 4 );
155         outb ( ++t509->current_tag, t509->id_port ); /* tag */
156         outb ( ( 0xe0 | iobase ), t509->id_port ); /* activate */
157
158         return 1;
159 }
160
161 /*
162  * Find a t509 device matching the specified driver.  ("Matching the
163  * specified driver" is, in this case, a no-op, but we want to
164  * preserve the common bus API).
165  *
166  * Called only once, so inlined for efficiency.
167  *
168  */
169 static inline int find_t509_device ( struct t509_device *t509,
170                                      struct t509_driver *driver __unused ) {
171
172         /* Initialise struct t509 if it's the first time it's been used. */
173         if ( t509->magic != t509_magic ) {
174                 memset ( t509, 0, sizeof ( *t509 ) );
175                 t509->magic = t509_magic;
176                 if ( ! find_id_port ( t509 ) ) {
177                         DBG ( "No ID port available for contention select\n" );
178                         return 0;
179                 }
180         }
181
182         /* Find the next t509 device */
183         if ( ! fill_t509_device ( t509 ) )
184                 return 0;
185         
186         return 1;
187 }
188
189 /*
190  * Find the next T509 device that can be used to boot using the
191  * specified driver.
192  *
193  */
194 int find_t509_boot_device ( struct dev *dev, struct t509_driver *driver ) {
195         struct t509_device *t509 = ( struct t509_device * )dev->bus;
196
197         if ( ! find_t509_device ( t509, driver ) )
198                 return 0;
199
200         dev->name = driver->name;
201         dev->devid.bus_type = ISA_BUS_TYPE;
202         dev->devid.vendor_id = MFG_ID;
203         dev->devid.device_id = PROD_ID;
204         return 1;
205 }
206
207 /*
208  * The ISA probe function
209  *
210  */
211 static int el3_t509_probe ( struct dev *dev, struct t509_device *t509 ) {
212         struct nic *nic = nic_device ( dev );
213         
214         nic->ioaddr = t509->ioaddr;
215         nic->irqno = 0;
216         printf ( "3c509 board on ISA at %#hx - ", nic->ioaddr );
217
218         /* Hand off to generic t5x9 probe routine */
219         return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
220 }
221
222 static struct t509_driver el3_t509_driver = { "3c509 (ISA)" };
223
224 BOOT_DRIVER ( "3c509", find_t509_boot_device, el3_t509_driver,
225               el3_t509_probe );
226
227 /*
228  * The EISA probe function
229  *
230  */
231 static int el3_eisa_probe ( struct dev *dev, struct eisa_device *eisa ) {
232         struct nic *nic = nic_device ( dev );
233         
234         enable_eisa_device ( eisa );
235         nic->ioaddr = eisa->ioaddr;
236         nic->irqno = 0;
237         printf ( "3C5x9 board on EISA at %#hx - ", nic->ioaddr );
238
239         /* Hand off to generic t5x9 probe routine */
240         return t5x9_probe ( nic, ISA_PROD_ID ( PROD_ID ), ISA_PROD_ID_MASK );
241 }
242
243 static struct eisa_id el3_eisa_adapters[] = {
244         { "3Com 3c509 EtherLink III (EISA)", MFG_ID, PROD_ID },
245 };
246
247 static struct eisa_driver el3_eisa_driver =
248         EISA_DRIVER ( "3c509 (EISA)", el3_eisa_adapters );
249
250 BOOT_DRIVER ( "3c509 (EISA)", find_eisa_boot_device, el3_eisa_driver,
251               el3_eisa_probe );
252
253 /*
254  * We currently build both ISA and EISA support into a single ROM
255  * image, though there's no reason why this couldn't be split to
256  * reduce code size; just split this .c file into two in the obvious
257  * place.
258  *
259  */
260 ISA_ROM ( "3c509","3c509, ISA/EISA" );
261