diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/eth16i.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/eth16i.c')
-rw-r--r-- | drivers/net/eth16i.c | 1509 |
1 files changed, 1509 insertions, 0 deletions
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c new file mode 100644 index 000000000000..ccae6ba5f7c5 --- /dev/null +++ b/drivers/net/eth16i.c | |||
@@ -0,0 +1,1509 @@ | |||
1 | /* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux | ||
2 | |||
3 | Written 1994-1999 by Mika Kuoppala | ||
4 | |||
5 | Copyright (C) 1994-1999 by Mika Kuoppala | ||
6 | Based on skeleton.c and heavily on at1700.c by Donald Becker | ||
7 | |||
8 | This software may be used and distributed according to the terms | ||
9 | of the GNU General Public License, incorporated herein by reference. | ||
10 | |||
11 | The author may be reached as miku@iki.fi | ||
12 | |||
13 | This driver supports following cards : | ||
14 | - ICL EtherTeam 16i | ||
15 | - ICL EtherTeam 32 EISA | ||
16 | (Uses true 32 bit transfers rather than 16i compability mode) | ||
17 | |||
18 | Example Module usage: | ||
19 | insmod eth16i.o io=0x2a0 mediatype=bnc | ||
20 | |||
21 | mediatype can be one of the following: bnc,tp,dix,auto,eprom | ||
22 | |||
23 | 'auto' will try to autoprobe mediatype. | ||
24 | 'eprom' will use whatever type defined in eprom. | ||
25 | |||
26 | I have benchmarked driver with PII/300Mhz as a ftp client | ||
27 | and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec. | ||
28 | |||
29 | Sources: | ||
30 | - skeleton.c a sample network driver core for linux, | ||
31 | written by Donald Becker <becker@scyld.com> | ||
32 | - at1700.c a driver for Allied Telesis AT1700, written | ||
33 | by Donald Becker. | ||
34 | - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i | ||
35 | written by Markku Viima | ||
36 | - The Fujitsu MB86965 databook. | ||
37 | |||
38 | Author thanks following persons due to their valueble assistance: | ||
39 | Markku Viima (ICL) | ||
40 | Ari Valve (ICL) | ||
41 | Donald Becker | ||
42 | Kurt Huwig <kurt@huwig.de> | ||
43 | |||
44 | Revision history: | ||
45 | |||
46 | Version Date Description | ||
47 | |||
48 | 0.01 15.12-94 Initial version (card detection) | ||
49 | 0.02 23.01-95 Interrupt is now hooked correctly | ||
50 | 0.03 01.02-95 Rewrote initialization part | ||
51 | 0.04 07.02-95 Base skeleton done... | ||
52 | Made a few changes to signature checking | ||
53 | to make it a bit reliable. | ||
54 | - fixed bug in tx_buf mapping | ||
55 | - fixed bug in initialization (DLC_EN | ||
56 | wasn't enabled when initialization | ||
57 | was done.) | ||
58 | 0.05 08.02-95 If there were more than one packet to send, | ||
59 | transmit was jammed due to invalid | ||
60 | register write...now fixed | ||
61 | 0.06 19.02-95 Rewrote interrupt handling | ||
62 | 0.07 13.04-95 Wrote EEPROM read routines | ||
63 | Card configuration now set according to | ||
64 | data read from EEPROM | ||
65 | 0.08 23.06-95 Wrote part that tries to probe used interface | ||
66 | port if AUTO is selected | ||
67 | |||
68 | 0.09 01.09-95 Added module support | ||
69 | |||
70 | 0.10 04.09-95 Fixed receive packet allocation to work | ||
71 | with kernels > 1.3.x | ||
72 | |||
73 | 0.20 20.09-95 Added support for EtherTeam32 EISA | ||
74 | |||
75 | 0.21 17.10-95 Removed the unnecessary extern | ||
76 | init_etherdev() declaration. Some | ||
77 | other cleanups. | ||
78 | |||
79 | 0.22 22.02-96 Receive buffer was not flushed | ||
80 | correctly when faulty packet was | ||
81 | received. Now fixed. | ||
82 | |||
83 | 0.23 26.02-96 Made resetting the adapter | ||
84 | more reliable. | ||
85 | |||
86 | 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx | ||
87 | |||
88 | 0.25 22.05-96 kfree() was missing from cleanup_module. | ||
89 | |||
90 | 0.26 11.06-96 Sometimes card was not found by | ||
91 | check_signature(). Now made more reliable. | ||
92 | |||
93 | 0.27 23.06-96 Oops. 16 consecutive collisions halted | ||
94 | adapter. Now will try to retransmit | ||
95 | MAX_COL_16 times before finally giving up. | ||
96 | |||
97 | 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq | ||
98 | |||
99 | 0.29 29.10-97 Multiple card support for module users | ||
100 | |||
101 | 0.30 30.10-97 Fixed irq allocation bug. | ||
102 | (request_irq moved from probe to open) | ||
103 | |||
104 | 0.30a 21.08-98 Card detection made more relaxed. Driver | ||
105 | had problems with some TCP/IP-PROM boots | ||
106 | to find the card. Suggested by | ||
107 | Kurt Huwig <kurt@huwig.de> | ||
108 | |||
109 | 0.31 28.08-98 Media interface port can now be selected | ||
110 | with module parameters or kernel | ||
111 | boot parameters. | ||
112 | |||
113 | 0.32 31.08-98 IRQ was never freed if open/close | ||
114 | pair wasn't called. Now fixed. | ||
115 | |||
116 | 0.33 10.09-98 When eth16i_open() was called after | ||
117 | eth16i_close() chip never recovered. | ||
118 | Now more shallow reset is made on | ||
119 | close. | ||
120 | |||
121 | 0.34 29.06-99 Fixed one bad #ifdef. | ||
122 | Changed ioaddr -> io for consistency | ||
123 | |||
124 | 0.35 01.07-99 transmit,-receive bytes were never | ||
125 | updated in stats. | ||
126 | |||
127 | Bugs: | ||
128 | In some cases the media interface autoprobing code doesn't find | ||
129 | the correct interface type. In this case you can | ||
130 | manually choose the interface type in DOS with E16IC.EXE which is | ||
131 | configuration software for EtherTeam16i and EtherTeam32 cards. | ||
132 | This is also true for IRQ setting. You cannot use module | ||
133 | parameter to configure IRQ of the card (yet). | ||
134 | |||
135 | To do: | ||
136 | - Real multicast support | ||
137 | - Rewrite the media interface autoprobing code. Its _horrible_ ! | ||
138 | - Possibly merge all the MB86965 specific code to external | ||
139 | module for use by eth16.c and Donald's at1700.c | ||
140 | - IRQ configuration with module parameter. I will do | ||
141 | this when i will get enough info about setting | ||
142 | irq without configuration utility. | ||
143 | */ | ||
144 | |||
145 | static char *version = | ||
146 | "eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n"; | ||
147 | |||
148 | #include <linux/module.h> | ||
149 | #include <linux/kernel.h> | ||
150 | #include <linux/types.h> | ||
151 | #include <linux/fcntl.h> | ||
152 | #include <linux/interrupt.h> | ||
153 | #include <linux/ioport.h> | ||
154 | #include <linux/in.h> | ||
155 | #include <linux/slab.h> | ||
156 | #include <linux/string.h> | ||
157 | #include <linux/errno.h> | ||
158 | #include <linux/init.h> | ||
159 | #include <linux/spinlock.h> | ||
160 | #include <linux/netdevice.h> | ||
161 | #include <linux/etherdevice.h> | ||
162 | #include <linux/skbuff.h> | ||
163 | #include <linux/bitops.h> | ||
164 | |||
165 | #include <asm/system.h> | ||
166 | #include <asm/io.h> | ||
167 | #include <asm/dma.h> | ||
168 | |||
169 | |||
170 | |||
171 | /* Few macros */ | ||
172 | #define BIT(a) ( (1 << (a)) ) | ||
173 | #define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr))) | ||
174 | #define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr))) | ||
175 | |||
176 | /* This is the I/O address space for Etherteam 16i adapter. */ | ||
177 | #define ETH16I_IO_EXTENT 32 | ||
178 | |||
179 | /* Ticks before deciding that transmit has timed out */ | ||
180 | #define TX_TIMEOUT (400*HZ/1000) | ||
181 | |||
182 | /* Maximum loop count when receiving packets */ | ||
183 | #define MAX_RX_LOOP 20 | ||
184 | |||
185 | /* Some interrupt masks */ | ||
186 | #define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */ | ||
187 | #define ETH16I_INTR_OFF 0x0000 | ||
188 | |||
189 | /* Buffers header status byte meanings */ | ||
190 | #define PKT_GOOD BIT(5) | ||
191 | #define PKT_GOOD_RMT BIT(4) | ||
192 | #define PKT_SHORT BIT(3) | ||
193 | #define PKT_ALIGN_ERR BIT(2) | ||
194 | #define PKT_CRC_ERR BIT(1) | ||
195 | #define PKT_RX_BUF_OVERFLOW BIT(0) | ||
196 | |||
197 | /* Transmit status register (DLCR0) */ | ||
198 | #define TX_STATUS_REG 0 | ||
199 | #define TX_DONE BIT(7) | ||
200 | #define NET_BUSY BIT(6) | ||
201 | #define TX_PKT_RCD BIT(5) | ||
202 | #define CR_LOST BIT(4) | ||
203 | #define TX_JABBER_ERR BIT(3) | ||
204 | #define COLLISION BIT(2) | ||
205 | #define COLLISIONS_16 BIT(1) | ||
206 | |||
207 | /* Receive status register (DLCR1) */ | ||
208 | #define RX_STATUS_REG 1 | ||
209 | #define RX_PKT BIT(7) /* Packet received */ | ||
210 | #define BUS_RD_ERR BIT(6) | ||
211 | #define SHORT_PKT_ERR BIT(3) | ||
212 | #define ALIGN_ERR BIT(2) | ||
213 | #define CRC_ERR BIT(1) | ||
214 | #define RX_BUF_OVERFLOW BIT(0) | ||
215 | |||
216 | /* Transmit Interrupt Enable Register (DLCR2) */ | ||
217 | #define TX_INTR_REG 2 | ||
218 | #define TX_INTR_DONE BIT(7) | ||
219 | #define TX_INTR_COL BIT(2) | ||
220 | #define TX_INTR_16_COL BIT(1) | ||
221 | |||
222 | /* Receive Interrupt Enable Register (DLCR3) */ | ||
223 | #define RX_INTR_REG 3 | ||
224 | #define RX_INTR_RECEIVE BIT(7) | ||
225 | #define RX_INTR_SHORT_PKT BIT(3) | ||
226 | #define RX_INTR_CRC_ERR BIT(1) | ||
227 | #define RX_INTR_BUF_OVERFLOW BIT(0) | ||
228 | |||
229 | /* Transmit Mode Register (DLCR4) */ | ||
230 | #define TRANSMIT_MODE_REG 4 | ||
231 | #define LOOPBACK_CONTROL BIT(1) | ||
232 | #define CONTROL_OUTPUT BIT(2) | ||
233 | |||
234 | /* Receive Mode Register (DLCR5) */ | ||
235 | #define RECEIVE_MODE_REG 5 | ||
236 | #define RX_BUFFER_EMPTY BIT(6) | ||
237 | #define ACCEPT_BAD_PACKETS BIT(5) | ||
238 | #define RECEIVE_SHORT_ADDR BIT(4) | ||
239 | #define ACCEPT_SHORT_PACKETS BIT(3) | ||
240 | #define REMOTE_RESET BIT(2) | ||
241 | |||
242 | #define ADDRESS_FILTER_MODE BIT(1) | BIT(0) | ||
243 | #define REJECT_ALL 0 | ||
244 | #define ACCEPT_ALL 3 | ||
245 | #define MODE_1 1 /* NODE ID, BC, MC, 2-24th bit */ | ||
246 | #define MODE_2 2 /* NODE ID, BC, MC, Hash Table */ | ||
247 | |||
248 | /* Configuration Register 0 (DLCR6) */ | ||
249 | #define CONFIG_REG_0 6 | ||
250 | #define DLC_EN BIT(7) | ||
251 | #define SRAM_CYCLE_TIME_100NS BIT(6) | ||
252 | #define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */ | ||
253 | #define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */ | ||
254 | #define TBS1 BIT(3) | ||
255 | #define TBS0 BIT(2) | ||
256 | #define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */ | ||
257 | #define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */ | ||
258 | |||
259 | #ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */ | ||
260 | #define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */ | ||
261 | #endif | ||
262 | #define TX_BUF_1x2048 0 | ||
263 | #define TX_BUF_2x2048 1 | ||
264 | #define TX_BUF_2x4098 2 | ||
265 | #define TX_BUF_2x8192 3 | ||
266 | |||
267 | /* Configuration Register 1 (DLCR7) */ | ||
268 | #define CONFIG_REG_1 7 | ||
269 | #define POWERUP BIT(5) | ||
270 | |||
271 | /* Transmit start register */ | ||
272 | #define TRANSMIT_START_REG 10 | ||
273 | #define TRANSMIT_START_RB 2 | ||
274 | #define TX_START BIT(7) /* Rest of register bit indicate*/ | ||
275 | /* number of packets in tx buffer*/ | ||
276 | /* Node ID registers (DLCR8-13) */ | ||
277 | #define NODE_ID_0 8 | ||
278 | #define NODE_ID_RB 0 | ||
279 | |||
280 | /* Hash Table registers (HT8-15) */ | ||
281 | #define HASH_TABLE_0 8 | ||
282 | #define HASH_TABLE_RB 1 | ||
283 | |||
284 | /* Buffer memory ports */ | ||
285 | #define BUFFER_MEM_PORT_LB 8 | ||
286 | #define DATAPORT BUFFER_MEM_PORT_LB | ||
287 | #define BUFFER_MEM_PORT_HB 9 | ||
288 | |||
289 | /* 16 Collision control register (BMPR11) */ | ||
290 | #define COL_16_REG 11 | ||
291 | #define HALT_ON_16 0x00 | ||
292 | #define RETRANS_AND_HALT_ON_16 0x02 | ||
293 | |||
294 | /* Maximum number of attempts to send after 16 concecutive collisions */ | ||
295 | #define MAX_COL_16 10 | ||
296 | |||
297 | /* DMA Burst and Transceiver Mode Register (BMPR13) */ | ||
298 | #define TRANSCEIVER_MODE_REG 13 | ||
299 | #define TRANSCEIVER_MODE_RB 2 | ||
300 | #define IO_BASE_UNLOCK BIT(7) | ||
301 | #define LOWER_SQUELCH_TRESH BIT(6) | ||
302 | #define LINK_TEST_DISABLE BIT(5) | ||
303 | #define AUI_SELECT BIT(4) | ||
304 | #define DIS_AUTO_PORT_SEL BIT(3) | ||
305 | |||
306 | /* Filter Self Receive Register (BMPR14) */ | ||
307 | #define FILTER_SELF_RX_REG 14 | ||
308 | #define SKIP_RX_PACKET BIT(2) | ||
309 | #define FILTER_SELF_RECEIVE BIT(0) | ||
310 | |||
311 | /* EEPROM Control Register (BMPR 16) */ | ||
312 | #define EEPROM_CTRL_REG 16 | ||
313 | |||
314 | /* EEPROM Data Register (BMPR 17) */ | ||
315 | #define EEPROM_DATA_REG 17 | ||
316 | |||
317 | /* NMC93CSx6 EEPROM Control Bits */ | ||
318 | #define CS_0 0x00 | ||
319 | #define CS_1 0x20 | ||
320 | #define SK_0 0x00 | ||
321 | #define SK_1 0x40 | ||
322 | #define DI_0 0x00 | ||
323 | #define DI_1 0x80 | ||
324 | |||
325 | /* NMC93CSx6 EEPROM Instructions */ | ||
326 | #define EEPROM_READ 0x80 | ||
327 | |||
328 | /* NMC93CSx6 EEPROM Addresses */ | ||
329 | #define E_NODEID_0 0x02 | ||
330 | #define E_NODEID_1 0x03 | ||
331 | #define E_NODEID_2 0x04 | ||
332 | #define E_PORT_SELECT 0x14 | ||
333 | #define E_PORT_BNC 0x00 | ||
334 | #define E_PORT_DIX 0x01 | ||
335 | #define E_PORT_TP 0x02 | ||
336 | #define E_PORT_AUTO 0x03 | ||
337 | #define E_PORT_FROM_EPROM 0x04 | ||
338 | #define E_PRODUCT_CFG 0x30 | ||
339 | |||
340 | |||
341 | /* Macro to slow down io between EEPROM clock transitions */ | ||
342 | #define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0) | ||
343 | |||
344 | /* Jumperless Configuration Register (BMPR19) */ | ||
345 | #define JUMPERLESS_CONFIG 19 | ||
346 | |||
347 | /* ID ROM registers, writing to them also resets some parts of chip */ | ||
348 | #define ID_ROM_0 24 | ||
349 | #define ID_ROM_7 31 | ||
350 | #define RESET ID_ROM_0 | ||
351 | |||
352 | /* This is the I/O address list to be probed when seeking the card */ | ||
353 | static unsigned int eth16i_portlist[] __initdata = { | ||
354 | 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 | ||
355 | }; | ||
356 | |||
357 | static unsigned int eth32i_portlist[] __initdata = { | ||
358 | 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, | ||
359 | 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 | ||
360 | }; | ||
361 | |||
362 | /* This is the Interrupt lookup table for Eth16i card */ | ||
363 | static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 }; | ||
364 | #define NUM_OF_ISA_IRQS 4 | ||
365 | |||
366 | /* This is the Interrupt lookup table for Eth32i card */ | ||
367 | static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 }; | ||
368 | #define EISA_IRQ_REG 0xc89 | ||
369 | #define NUM_OF_EISA_IRQS 8 | ||
370 | |||
371 | static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; | ||
372 | |||
373 | /* Use 0 for production, 1 for verification, >2 for debug */ | ||
374 | #ifndef ETH16I_DEBUG | ||
375 | #define ETH16I_DEBUG 0 | ||
376 | #endif | ||
377 | static unsigned int eth16i_debug = ETH16I_DEBUG; | ||
378 | |||
379 | /* Information for each board */ | ||
380 | |||
381 | struct eth16i_local { | ||
382 | struct net_device_stats stats; | ||
383 | unsigned char tx_started; | ||
384 | unsigned char tx_buf_busy; | ||
385 | unsigned short tx_queue; /* Number of packets in transmit buffer */ | ||
386 | unsigned short tx_queue_len; | ||
387 | unsigned int tx_buf_size; | ||
388 | unsigned long open_time; | ||
389 | unsigned long tx_buffered_packets; | ||
390 | unsigned long tx_buffered_bytes; | ||
391 | unsigned long col_16; | ||
392 | spinlock_t lock; | ||
393 | }; | ||
394 | |||
395 | /* Function prototypes */ | ||
396 | |||
397 | static int eth16i_probe1(struct net_device *dev, int ioaddr); | ||
398 | static int eth16i_check_signature(int ioaddr); | ||
399 | static int eth16i_probe_port(int ioaddr); | ||
400 | static void eth16i_set_port(int ioaddr, int porttype); | ||
401 | static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l); | ||
402 | static int eth16i_receive_probe_packet(int ioaddr); | ||
403 | static int eth16i_get_irq(int ioaddr); | ||
404 | static int eth16i_read_eeprom(int ioaddr, int offset); | ||
405 | static int eth16i_read_eeprom_word(int ioaddr); | ||
406 | static void eth16i_eeprom_cmd(int ioaddr, unsigned char command); | ||
407 | static int eth16i_open(struct net_device *dev); | ||
408 | static int eth16i_close(struct net_device *dev); | ||
409 | static int eth16i_tx(struct sk_buff *skb, struct net_device *dev); | ||
410 | static void eth16i_rx(struct net_device *dev); | ||
411 | static void eth16i_timeout(struct net_device *dev); | ||
412 | static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); | ||
413 | static void eth16i_reset(struct net_device *dev); | ||
414 | static void eth16i_timeout(struct net_device *dev); | ||
415 | static void eth16i_skip_packet(struct net_device *dev); | ||
416 | static void eth16i_multicast(struct net_device *dev); | ||
417 | static void eth16i_select_regbank(unsigned char regbank, int ioaddr); | ||
418 | static void eth16i_initialize(struct net_device *dev, int boot); | ||
419 | |||
420 | #if 0 | ||
421 | static int eth16i_set_irq(struct net_device *dev); | ||
422 | #endif | ||
423 | |||
424 | #ifdef MODULE | ||
425 | static ushort eth16i_parse_mediatype(const char* s); | ||
426 | #endif | ||
427 | |||
428 | static struct net_device_stats *eth16i_get_stats(struct net_device *dev); | ||
429 | |||
430 | static char cardname[] __initdata = "ICL EtherTeam 16i/32"; | ||
431 | |||
432 | static int __init do_eth16i_probe(struct net_device *dev) | ||
433 | { | ||
434 | int i; | ||
435 | int ioaddr; | ||
436 | int base_addr = dev->base_addr; | ||
437 | |||
438 | SET_MODULE_OWNER(dev); | ||
439 | |||
440 | if(eth16i_debug > 4) | ||
441 | printk(KERN_DEBUG "Probing started for %s\n", cardname); | ||
442 | |||
443 | if(base_addr > 0x1ff) /* Check only single location */ | ||
444 | return eth16i_probe1(dev, base_addr); | ||
445 | else if(base_addr != 0) /* Don't probe at all */ | ||
446 | return -ENXIO; | ||
447 | |||
448 | /* Seek card from the ISA io address space */ | ||
449 | for(i = 0; (ioaddr = eth16i_portlist[i]) ; i++) | ||
450 | if(eth16i_probe1(dev, ioaddr) == 0) | ||
451 | return 0; | ||
452 | |||
453 | /* Seek card from the EISA io address space */ | ||
454 | for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) | ||
455 | if(eth16i_probe1(dev, ioaddr) == 0) | ||
456 | return 0; | ||
457 | |||
458 | return -ENODEV; | ||
459 | } | ||
460 | |||
461 | #ifndef MODULE | ||
462 | struct net_device * __init eth16i_probe(int unit) | ||
463 | { | ||
464 | struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local)); | ||
465 | int err; | ||
466 | |||
467 | if (!dev) | ||
468 | return ERR_PTR(-ENOMEM); | ||
469 | |||
470 | sprintf(dev->name, "eth%d", unit); | ||
471 | netdev_boot_setup_check(dev); | ||
472 | |||
473 | err = do_eth16i_probe(dev); | ||
474 | if (err) | ||
475 | goto out; | ||
476 | err = register_netdev(dev); | ||
477 | if (err) | ||
478 | goto out1; | ||
479 | return dev; | ||
480 | out1: | ||
481 | free_irq(dev->irq, dev); | ||
482 | release_region(dev->base_addr, ETH16I_IO_EXTENT); | ||
483 | out: | ||
484 | free_netdev(dev); | ||
485 | return ERR_PTR(err); | ||
486 | } | ||
487 | #endif | ||
488 | |||
489 | static int __init eth16i_probe1(struct net_device *dev, int ioaddr) | ||
490 | { | ||
491 | struct eth16i_local *lp = netdev_priv(dev); | ||
492 | static unsigned version_printed; | ||
493 | int retval; | ||
494 | |||
495 | /* Let's grab the region */ | ||
496 | if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname)) | ||
497 | return -EBUSY; | ||
498 | |||
499 | /* | ||
500 | The MB86985 chip has on register which holds information in which | ||
501 | io address the chip lies. First read this register and compare | ||
502 | it to our current io address and if match then this could | ||
503 | be our chip. | ||
504 | */ | ||
505 | |||
506 | if(ioaddr < 0x1000) { | ||
507 | if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] | ||
508 | != ioaddr) { | ||
509 | retval = -ENODEV; | ||
510 | goto out; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | /* Now we will go a bit deeper and try to find the chip's signature */ | ||
515 | |||
516 | if(eth16i_check_signature(ioaddr) != 0) { | ||
517 | retval = -ENODEV; | ||
518 | goto out; | ||
519 | } | ||
520 | |||
521 | /* | ||
522 | Now it seems that we have found a ethernet chip in this particular | ||
523 | ioaddr. The MB86985 chip has this feature, that when you read a | ||
524 | certain register it will increase it's io base address to next | ||
525 | configurable slot. Now when we have found the chip, first thing is | ||
526 | to make sure that the chip's ioaddr will hold still here. | ||
527 | */ | ||
528 | |||
529 | eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); | ||
530 | outb(0x00, ioaddr + TRANSCEIVER_MODE_REG); | ||
531 | |||
532 | outb(0x00, ioaddr + RESET); /* Reset some parts of chip */ | ||
533 | BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* Disable the data link */ | ||
534 | |||
535 | if( (eth16i_debug & version_printed++) == 0) | ||
536 | printk(KERN_INFO "%s", version); | ||
537 | |||
538 | dev->base_addr = ioaddr; | ||
539 | dev->irq = eth16i_get_irq(ioaddr); | ||
540 | |||
541 | /* Try to obtain interrupt vector */ | ||
542 | |||
543 | if ((retval = request_irq(dev->irq, (void *)ð16i_interrupt, 0, cardname, dev))) { | ||
544 | printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n", | ||
545 | cardname, ioaddr, dev->irq); | ||
546 | goto out; | ||
547 | } | ||
548 | |||
549 | printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ", | ||
550 | dev->name, cardname, ioaddr, dev->irq); | ||
551 | |||
552 | |||
553 | /* Now we will have to lock the chip's io address */ | ||
554 | eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); | ||
555 | outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); | ||
556 | |||
557 | eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */ | ||
558 | |||
559 | /* Now let's same some energy by shutting down the chip ;) */ | ||
560 | BITCLR(ioaddr + CONFIG_REG_1, POWERUP); | ||
561 | |||
562 | /* Initialize the device structure */ | ||
563 | memset(lp, 0, sizeof(struct eth16i_local)); | ||
564 | dev->open = eth16i_open; | ||
565 | dev->stop = eth16i_close; | ||
566 | dev->hard_start_xmit = eth16i_tx; | ||
567 | dev->get_stats = eth16i_get_stats; | ||
568 | dev->set_multicast_list = eth16i_multicast; | ||
569 | dev->tx_timeout = eth16i_timeout; | ||
570 | dev->watchdog_timeo = TX_TIMEOUT; | ||
571 | spin_lock_init(&lp->lock); | ||
572 | return 0; | ||
573 | out: | ||
574 | release_region(ioaddr, ETH16I_IO_EXTENT); | ||
575 | return retval; | ||
576 | } | ||
577 | |||
578 | |||
579 | static void eth16i_initialize(struct net_device *dev, int boot) | ||
580 | { | ||
581 | int ioaddr = dev->base_addr; | ||
582 | int i, node_w = 0; | ||
583 | unsigned char node_byte = 0; | ||
584 | |||
585 | /* Setup station address */ | ||
586 | eth16i_select_regbank(NODE_ID_RB, ioaddr); | ||
587 | for(i = 0 ; i < 3 ; i++) { | ||
588 | unsigned short node_val = eth16i_read_eeprom(ioaddr, E_NODEID_0 + i); | ||
589 | ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val); | ||
590 | } | ||
591 | |||
592 | for(i = 0; i < 6; i++) { | ||
593 | outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i); | ||
594 | if(boot) { | ||
595 | printk("%02x", inb(ioaddr + NODE_ID_0 + i)); | ||
596 | if(i != 5) | ||
597 | printk(":"); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | /* Now we will set multicast addresses to accept none */ | ||
602 | eth16i_select_regbank(HASH_TABLE_RB, ioaddr); | ||
603 | for(i = 0; i < 8; i++) | ||
604 | outb(0x00, ioaddr + HASH_TABLE_0 + i); | ||
605 | |||
606 | /* | ||
607 | Now let's disable the transmitter and receiver, set the buffer ram | ||
608 | cycle time, bus width and buffer data path width. Also we shall | ||
609 | set transmit buffer size and total buffer size. | ||
610 | */ | ||
611 | |||
612 | eth16i_select_regbank(2, ioaddr); | ||
613 | |||
614 | node_byte = 0; | ||
615 | node_w = eth16i_read_eeprom(ioaddr, E_PRODUCT_CFG); | ||
616 | |||
617 | if( (node_w & 0xFF00) == 0x0800) | ||
618 | node_byte |= BUFFER_WIDTH_8; | ||
619 | |||
620 | node_byte |= SRAM_BS1; | ||
621 | |||
622 | if( (node_w & 0x00FF) == 64) | ||
623 | node_byte |= SRAM_BS0; | ||
624 | |||
625 | node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2); | ||
626 | |||
627 | outb(node_byte, ioaddr + CONFIG_REG_0); | ||
628 | |||
629 | /* We shall halt the transmitting, if 16 collisions are detected */ | ||
630 | outb(HALT_ON_16, ioaddr + COL_16_REG); | ||
631 | |||
632 | #ifdef MODULE | ||
633 | /* if_port already set by init_module() */ | ||
634 | #else | ||
635 | dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ? | ||
636 | dev->mem_start : E_PORT_FROM_EPROM; | ||
637 | #endif | ||
638 | |||
639 | /* Set interface port type */ | ||
640 | if(boot) { | ||
641 | char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" }; | ||
642 | |||
643 | switch(dev->if_port) | ||
644 | { | ||
645 | |||
646 | case E_PORT_FROM_EPROM: | ||
647 | dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT); | ||
648 | break; | ||
649 | |||
650 | case E_PORT_AUTO: | ||
651 | dev->if_port = eth16i_probe_port(ioaddr); | ||
652 | break; | ||
653 | |||
654 | case E_PORT_BNC: | ||
655 | case E_PORT_TP: | ||
656 | case E_PORT_DIX: | ||
657 | break; | ||
658 | } | ||
659 | |||
660 | printk(" %s interface.\n", porttype[dev->if_port]); | ||
661 | |||
662 | eth16i_set_port(ioaddr, dev->if_port); | ||
663 | } | ||
664 | |||
665 | /* Set Receive Mode to normal operation */ | ||
666 | outb(MODE_2, ioaddr + RECEIVE_MODE_REG); | ||
667 | } | ||
668 | |||
669 | static int eth16i_probe_port(int ioaddr) | ||
670 | { | ||
671 | int i; | ||
672 | int retcode; | ||
673 | unsigned char dummy_packet[64]; | ||
674 | |||
675 | /* Powerup the chip */ | ||
676 | outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); | ||
677 | |||
678 | BITSET(ioaddr + CONFIG_REG_0, DLC_EN); | ||
679 | |||
680 | eth16i_select_regbank(NODE_ID_RB, ioaddr); | ||
681 | |||
682 | for(i = 0; i < 6; i++) { | ||
683 | dummy_packet[i] = inb(ioaddr + NODE_ID_0 + i); | ||
684 | dummy_packet[i+6] = inb(ioaddr + NODE_ID_0 + i); | ||
685 | } | ||
686 | |||
687 | dummy_packet[12] = 0x00; | ||
688 | dummy_packet[13] = 0x04; | ||
689 | memset(dummy_packet + 14, 0, sizeof(dummy_packet) - 14); | ||
690 | |||
691 | eth16i_select_regbank(2, ioaddr); | ||
692 | |||
693 | for(i = 0; i < 3; i++) { | ||
694 | BITSET(ioaddr + CONFIG_REG_0, DLC_EN); | ||
695 | BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); | ||
696 | eth16i_set_port(ioaddr, i); | ||
697 | |||
698 | if(eth16i_debug > 1) | ||
699 | printk(KERN_DEBUG "Set port number %d\n", i); | ||
700 | |||
701 | retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64); | ||
702 | if(retcode == 0) { | ||
703 | retcode = eth16i_receive_probe_packet(ioaddr); | ||
704 | if(retcode != -1) { | ||
705 | if(eth16i_debug > 1) | ||
706 | printk(KERN_DEBUG "Eth16i interface port found at %d\n", i); | ||
707 | return i; | ||
708 | } | ||
709 | } | ||
710 | else { | ||
711 | if(eth16i_debug > 1) | ||
712 | printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n"); | ||
713 | } | ||
714 | } | ||
715 | |||
716 | if( eth16i_debug > 1) | ||
717 | printk(KERN_DEBUG "Using default port\n"); | ||
718 | |||
719 | return E_PORT_BNC; | ||
720 | } | ||
721 | |||
722 | static void eth16i_set_port(int ioaddr, int porttype) | ||
723 | { | ||
724 | unsigned short temp = 0; | ||
725 | |||
726 | eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); | ||
727 | outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG); | ||
728 | |||
729 | temp |= DIS_AUTO_PORT_SEL; | ||
730 | |||
731 | switch(porttype) { | ||
732 | |||
733 | case E_PORT_BNC : | ||
734 | temp |= AUI_SELECT; | ||
735 | break; | ||
736 | |||
737 | case E_PORT_TP : | ||
738 | break; | ||
739 | |||
740 | case E_PORT_DIX : | ||
741 | temp |= AUI_SELECT; | ||
742 | BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT); | ||
743 | break; | ||
744 | } | ||
745 | |||
746 | outb(temp, ioaddr + TRANSCEIVER_MODE_REG); | ||
747 | |||
748 | if(eth16i_debug > 1) { | ||
749 | printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG)); | ||
750 | printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n", | ||
751 | inb(ioaddr+TRANSCEIVER_MODE_REG)); | ||
752 | } | ||
753 | } | ||
754 | |||
755 | static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l) | ||
756 | { | ||
757 | int starttime; | ||
758 | |||
759 | outb(0xff, ioaddr + TX_STATUS_REG); | ||
760 | |||
761 | outw(l, ioaddr + DATAPORT); | ||
762 | outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); | ||
763 | |||
764 | starttime = jiffies; | ||
765 | outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); | ||
766 | |||
767 | while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) { | ||
768 | if( (jiffies - starttime) > TX_TIMEOUT) { | ||
769 | return -1; | ||
770 | } | ||
771 | } | ||
772 | |||
773 | return 0; | ||
774 | } | ||
775 | |||
776 | static int eth16i_receive_probe_packet(int ioaddr) | ||
777 | { | ||
778 | int starttime; | ||
779 | |||
780 | starttime = jiffies; | ||
781 | |||
782 | while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) { | ||
783 | if( (jiffies - starttime) > TX_TIMEOUT) { | ||
784 | |||
785 | if(eth16i_debug > 1) | ||
786 | printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n"); | ||
787 | starttime = jiffies; | ||
788 | while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) { | ||
789 | if( (jiffies - starttime) > TX_TIMEOUT) { | ||
790 | if(eth16i_debug > 1) | ||
791 | printk(KERN_DEBUG "Timeout occurred waiting receive packet\n"); | ||
792 | return -1; | ||
793 | } | ||
794 | } | ||
795 | |||
796 | if(eth16i_debug > 1) | ||
797 | printk(KERN_DEBUG "RECEIVE_PACKET\n"); | ||
798 | return(0); /* Found receive packet */ | ||
799 | } | ||
800 | } | ||
801 | |||
802 | if(eth16i_debug > 1) { | ||
803 | printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG)); | ||
804 | printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG)); | ||
805 | } | ||
806 | |||
807 | return(0); /* Return success */ | ||
808 | } | ||
809 | |||
810 | #if 0 | ||
811 | static int eth16i_set_irq(struct net_device* dev) | ||
812 | { | ||
813 | const int ioaddr = dev->base_addr; | ||
814 | const int irq = dev->irq; | ||
815 | int i = 0; | ||
816 | |||
817 | if(ioaddr < 0x1000) { | ||
818 | while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq) | ||
819 | i++; | ||
820 | |||
821 | if(i < NUM_OF_ISA_IRQS) { | ||
822 | u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG); | ||
823 | cbyte = (cbyte & 0x3F) | (i << 6); | ||
824 | outb(cbyte, ioaddr + JUMPERLESS_CONFIG); | ||
825 | return 0; | ||
826 | } | ||
827 | } | ||
828 | else { | ||
829 | printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name); | ||
830 | } | ||
831 | |||
832 | return -1; | ||
833 | |||
834 | } | ||
835 | #endif | ||
836 | |||
837 | static int __init eth16i_get_irq(int ioaddr) | ||
838 | { | ||
839 | unsigned char cbyte; | ||
840 | |||
841 | if( ioaddr < 0x1000) { | ||
842 | cbyte = inb(ioaddr + JUMPERLESS_CONFIG); | ||
843 | return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] ); | ||
844 | } else { /* Oh..the card is EISA so method getting IRQ different */ | ||
845 | unsigned short index = 0; | ||
846 | cbyte = inb(ioaddr + EISA_IRQ_REG); | ||
847 | while( (cbyte & 0x01) == 0) { | ||
848 | cbyte = cbyte >> 1; | ||
849 | index++; | ||
850 | } | ||
851 | return( eth32i_irqmap[ index ] ); | ||
852 | } | ||
853 | } | ||
854 | |||
855 | static int __init eth16i_check_signature(int ioaddr) | ||
856 | { | ||
857 | int i; | ||
858 | unsigned char creg[4] = { 0 }; | ||
859 | |||
860 | for(i = 0; i < 4 ; i++) { | ||
861 | |||
862 | creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i); | ||
863 | |||
864 | if(eth16i_debug > 1) | ||
865 | printk("eth16i: read signature byte %x at %x\n", | ||
866 | creg[i], | ||
867 | ioaddr + TRANSMIT_MODE_REG + i); | ||
868 | } | ||
869 | |||
870 | creg[0] &= 0x0F; /* Mask collision cnr */ | ||
871 | creg[2] &= 0x7F; /* Mask DCLEN bit */ | ||
872 | |||
873 | #if 0 | ||
874 | /* | ||
875 | This was removed because the card was sometimes left to state | ||
876 | from which it couldn't be find anymore. If there is need | ||
877 | to more strict check still this have to be fixed. | ||
878 | */ | ||
879 | if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) { | ||
880 | if(creg[1] != 0x42) | ||
881 | return -1; | ||
882 | } | ||
883 | #endif | ||
884 | |||
885 | if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) { | ||
886 | creg[2] &= 0x40; | ||
887 | creg[3] &= 0x03; | ||
888 | |||
889 | if( !((creg[2] == 0x40) && (creg[3] == 0x00)) ) | ||
890 | return -1; | ||
891 | } | ||
892 | |||
893 | if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0) | ||
894 | return -1; | ||
895 | |||
896 | if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00) | ||
897 | return -1; | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static int eth16i_read_eeprom(int ioaddr, int offset) | ||
903 | { | ||
904 | int data = 0; | ||
905 | |||
906 | eth16i_eeprom_cmd(ioaddr, EEPROM_READ | offset); | ||
907 | outb(CS_1, ioaddr + EEPROM_CTRL_REG); | ||
908 | data = eth16i_read_eeprom_word(ioaddr); | ||
909 | outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG); | ||
910 | |||
911 | return(data); | ||
912 | } | ||
913 | |||
914 | static int eth16i_read_eeprom_word(int ioaddr) | ||
915 | { | ||
916 | int i; | ||
917 | int data = 0; | ||
918 | |||
919 | for(i = 16; i > 0; i--) { | ||
920 | outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); | ||
921 | eeprom_slow_io(); | ||
922 | outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); | ||
923 | eeprom_slow_io(); | ||
924 | data = (data << 1) | | ||
925 | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0); | ||
926 | |||
927 | eeprom_slow_io(); | ||
928 | } | ||
929 | |||
930 | return(data); | ||
931 | } | ||
932 | |||
933 | static void eth16i_eeprom_cmd(int ioaddr, unsigned char command) | ||
934 | { | ||
935 | int i; | ||
936 | |||
937 | outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG); | ||
938 | outb(DI_0, ioaddr + EEPROM_DATA_REG); | ||
939 | outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); | ||
940 | outb(DI_1, ioaddr + EEPROM_DATA_REG); | ||
941 | outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); | ||
942 | |||
943 | for(i = 7; i >= 0; i--) { | ||
944 | short cmd = ( (command & (1 << i)) ? DI_1 : DI_0 ); | ||
945 | outb(cmd, ioaddr + EEPROM_DATA_REG); | ||
946 | outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); | ||
947 | eeprom_slow_io(); | ||
948 | outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); | ||
949 | eeprom_slow_io(); | ||
950 | } | ||
951 | } | ||
952 | |||
953 | static int eth16i_open(struct net_device *dev) | ||
954 | { | ||
955 | struct eth16i_local *lp = netdev_priv(dev); | ||
956 | int ioaddr = dev->base_addr; | ||
957 | |||
958 | /* Powerup the chip */ | ||
959 | outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); | ||
960 | |||
961 | /* Initialize the chip */ | ||
962 | eth16i_initialize(dev, 0); | ||
963 | |||
964 | /* Set the transmit buffer size */ | ||
965 | lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; | ||
966 | |||
967 | if(eth16i_debug > 0) | ||
968 | printk(KERN_DEBUG "%s: transmit buffer size %d\n", | ||
969 | dev->name, lp->tx_buf_size); | ||
970 | |||
971 | /* Now enable Transmitter and Receiver sections */ | ||
972 | BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); | ||
973 | |||
974 | /* Now switch to register bank 2, for run time operation */ | ||
975 | eth16i_select_regbank(2, ioaddr); | ||
976 | |||
977 | lp->open_time = jiffies; | ||
978 | lp->tx_started = 0; | ||
979 | lp->tx_queue = 0; | ||
980 | lp->tx_queue_len = 0; | ||
981 | |||
982 | /* Turn on interrupts*/ | ||
983 | outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); | ||
984 | |||
985 | netif_start_queue(dev); | ||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int eth16i_close(struct net_device *dev) | ||
990 | { | ||
991 | struct eth16i_local *lp = netdev_priv(dev); | ||
992 | int ioaddr = dev->base_addr; | ||
993 | |||
994 | eth16i_reset(dev); | ||
995 | |||
996 | /* Turn off interrupts*/ | ||
997 | outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); | ||
998 | |||
999 | netif_stop_queue(dev); | ||
1000 | |||
1001 | lp->open_time = 0; | ||
1002 | |||
1003 | /* Disable transmit and receive */ | ||
1004 | BITSET(ioaddr + CONFIG_REG_0, DLC_EN); | ||
1005 | |||
1006 | /* Reset the chip */ | ||
1007 | /* outb(0xff, ioaddr + RESET); */ | ||
1008 | /* outw(0xffff, ioaddr + TX_STATUS_REG); */ | ||
1009 | |||
1010 | outb(0x00, ioaddr + CONFIG_REG_1); | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static void eth16i_timeout(struct net_device *dev) | ||
1016 | { | ||
1017 | struct eth16i_local *lp = netdev_priv(dev); | ||
1018 | int ioaddr = dev->base_addr; | ||
1019 | /* | ||
1020 | If we get here, some higher level has decided that | ||
1021 | we are broken. There should really be a "kick me" | ||
1022 | function call instead. | ||
1023 | */ | ||
1024 | |||
1025 | outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); | ||
1026 | printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", | ||
1027 | dev->name, | ||
1028 | inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? | ||
1029 | "IRQ conflict" : "network cable problem"); | ||
1030 | |||
1031 | dev->trans_start = jiffies; | ||
1032 | |||
1033 | /* Let's dump all registers */ | ||
1034 | if(eth16i_debug > 0) { | ||
1035 | printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n", | ||
1036 | dev->name, inb(ioaddr + 0), | ||
1037 | inb(ioaddr + 1), inb(ioaddr + 2), | ||
1038 | inb(ioaddr + 3), inb(ioaddr + 4), | ||
1039 | inb(ioaddr + 5), | ||
1040 | inb(ioaddr + 6), inb(ioaddr + 7)); | ||
1041 | |||
1042 | printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n", | ||
1043 | dev->name, inb(ioaddr + TRANSMIT_START_REG), | ||
1044 | inb(ioaddr + COL_16_REG)); | ||
1045 | printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue); | ||
1046 | printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); | ||
1047 | printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); | ||
1048 | } | ||
1049 | lp->stats.tx_errors++; | ||
1050 | eth16i_reset(dev); | ||
1051 | dev->trans_start = jiffies; | ||
1052 | outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); | ||
1053 | netif_wake_queue(dev); | ||
1054 | } | ||
1055 | |||
1056 | static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) | ||
1057 | { | ||
1058 | struct eth16i_local *lp = netdev_priv(dev); | ||
1059 | int ioaddr = dev->base_addr; | ||
1060 | int status = 0; | ||
1061 | ushort length = skb->len; | ||
1062 | unsigned char *buf; | ||
1063 | unsigned long flags; | ||
1064 | |||
1065 | if (length < ETH_ZLEN) { | ||
1066 | skb = skb_padto(skb, ETH_ZLEN); | ||
1067 | if (skb == NULL) | ||
1068 | return 0; | ||
1069 | length = ETH_ZLEN; | ||
1070 | } | ||
1071 | buf = skb->data; | ||
1072 | |||
1073 | netif_stop_queue(dev); | ||
1074 | |||
1075 | /* Turn off TX interrupts */ | ||
1076 | outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); | ||
1077 | |||
1078 | /* We would be better doing the disable_irq tricks the 3c509 does, | ||
1079 | that would make this suck a lot less */ | ||
1080 | |||
1081 | spin_lock_irqsave(&lp->lock, flags); | ||
1082 | |||
1083 | if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) { | ||
1084 | if(eth16i_debug > 0) | ||
1085 | printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name); | ||
1086 | } | ||
1087 | else { | ||
1088 | outw(length, ioaddr + DATAPORT); | ||
1089 | |||
1090 | if( ioaddr < 0x1000 ) | ||
1091 | outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); | ||
1092 | else { | ||
1093 | unsigned char frag = length % 4; | ||
1094 | outsl(ioaddr + DATAPORT, buf, length >> 2); | ||
1095 | if( frag != 0 ) { | ||
1096 | outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1); | ||
1097 | if( frag == 3 ) | ||
1098 | outsw(ioaddr + DATAPORT, | ||
1099 | (buf + (length & 0xFFFC) + 2), 1); | ||
1100 | } | ||
1101 | } | ||
1102 | lp->tx_buffered_packets++; | ||
1103 | lp->tx_buffered_bytes = length; | ||
1104 | lp->tx_queue++; | ||
1105 | lp->tx_queue_len += length + 2; | ||
1106 | } | ||
1107 | lp->tx_buf_busy = 0; | ||
1108 | |||
1109 | if(lp->tx_started == 0) { | ||
1110 | /* If the transmitter is idle..always trigger a transmit */ | ||
1111 | outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG); | ||
1112 | lp->tx_queue = 0; | ||
1113 | lp->tx_queue_len = 0; | ||
1114 | dev->trans_start = jiffies; | ||
1115 | lp->tx_started = 1; | ||
1116 | netif_wake_queue(dev); | ||
1117 | } | ||
1118 | else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { | ||
1119 | /* There is still more room for one more packet in tx buffer */ | ||
1120 | netif_wake_queue(dev); | ||
1121 | } | ||
1122 | |||
1123 | spin_unlock_irqrestore(&lp->lock, flags); | ||
1124 | |||
1125 | outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); | ||
1126 | /* Turn TX interrupts back on */ | ||
1127 | /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ | ||
1128 | status = 0; | ||
1129 | dev_kfree_skb(skb); | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | static void eth16i_rx(struct net_device *dev) | ||
1134 | { | ||
1135 | struct eth16i_local *lp = netdev_priv(dev); | ||
1136 | int ioaddr = dev->base_addr; | ||
1137 | int boguscount = MAX_RX_LOOP; | ||
1138 | |||
1139 | /* Loop until all packets have been read */ | ||
1140 | while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) { | ||
1141 | |||
1142 | /* Read status byte from receive buffer */ | ||
1143 | ushort status = inw(ioaddr + DATAPORT); | ||
1144 | |||
1145 | /* Get the size of the packet from receive buffer */ | ||
1146 | ushort pkt_len = inw(ioaddr + DATAPORT); | ||
1147 | |||
1148 | if(eth16i_debug > 4) | ||
1149 | printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n", | ||
1150 | dev->name, | ||
1151 | inb(ioaddr + RECEIVE_MODE_REG), status); | ||
1152 | |||
1153 | if( !(status & PKT_GOOD) ) { | ||
1154 | lp->stats.rx_errors++; | ||
1155 | |||
1156 | if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) { | ||
1157 | lp->stats.rx_length_errors++; | ||
1158 | eth16i_reset(dev); | ||
1159 | return; | ||
1160 | } | ||
1161 | else { | ||
1162 | eth16i_skip_packet(dev); | ||
1163 | lp->stats.rx_dropped++; | ||
1164 | } | ||
1165 | } | ||
1166 | else { /* Ok so now we should have a good packet */ | ||
1167 | struct sk_buff *skb; | ||
1168 | |||
1169 | skb = dev_alloc_skb(pkt_len + 3); | ||
1170 | if( skb == NULL ) { | ||
1171 | printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", | ||
1172 | dev->name, pkt_len); | ||
1173 | eth16i_skip_packet(dev); | ||
1174 | lp->stats.rx_dropped++; | ||
1175 | break; | ||
1176 | } | ||
1177 | |||
1178 | skb->dev = dev; | ||
1179 | skb_reserve(skb,2); | ||
1180 | |||
1181 | /* | ||
1182 | Now let's get the packet out of buffer. | ||
1183 | size is (pkt_len + 1) >> 1, cause we are now reading words | ||
1184 | and it have to be even aligned. | ||
1185 | */ | ||
1186 | |||
1187 | if(ioaddr < 0x1000) | ||
1188 | insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), | ||
1189 | (pkt_len + 1) >> 1); | ||
1190 | else { | ||
1191 | unsigned char *buf = skb_put(skb, pkt_len); | ||
1192 | unsigned char frag = pkt_len % 4; | ||
1193 | |||
1194 | insl(ioaddr + DATAPORT, buf, pkt_len >> 2); | ||
1195 | |||
1196 | if(frag != 0) { | ||
1197 | unsigned short rest[2]; | ||
1198 | rest[0] = inw( ioaddr + DATAPORT ); | ||
1199 | if(frag == 3) | ||
1200 | rest[1] = inw( ioaddr + DATAPORT ); | ||
1201 | |||
1202 | memcpy(buf + (pkt_len & 0xfffc), (char *)rest, frag); | ||
1203 | } | ||
1204 | } | ||
1205 | |||
1206 | skb->protocol=eth_type_trans(skb, dev); | ||
1207 | |||
1208 | if( eth16i_debug > 5 ) { | ||
1209 | int i; | ||
1210 | printk(KERN_DEBUG "%s: Received packet of length %d.\n", | ||
1211 | dev->name, pkt_len); | ||
1212 | for(i = 0; i < 14; i++) | ||
1213 | printk(KERN_DEBUG " %02x", skb->data[i]); | ||
1214 | printk(KERN_DEBUG ".\n"); | ||
1215 | } | ||
1216 | netif_rx(skb); | ||
1217 | dev->last_rx = jiffies; | ||
1218 | lp->stats.rx_packets++; | ||
1219 | lp->stats.rx_bytes += pkt_len; | ||
1220 | |||
1221 | } /* else */ | ||
1222 | |||
1223 | if(--boguscount <= 0) | ||
1224 | break; | ||
1225 | |||
1226 | } /* while */ | ||
1227 | } | ||
1228 | |||
1229 | static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1230 | { | ||
1231 | struct net_device *dev = dev_id; | ||
1232 | struct eth16i_local *lp; | ||
1233 | int ioaddr = 0, status; | ||
1234 | int handled = 0; | ||
1235 | |||
1236 | ioaddr = dev->base_addr; | ||
1237 | lp = netdev_priv(dev); | ||
1238 | |||
1239 | /* Turn off all interrupts from adapter */ | ||
1240 | outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); | ||
1241 | |||
1242 | /* eth16i_tx won't be called */ | ||
1243 | spin_lock(&lp->lock); | ||
1244 | |||
1245 | status = inw(ioaddr + TX_STATUS_REG); /* Get the status */ | ||
1246 | outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */ | ||
1247 | |||
1248 | if (status) | ||
1249 | handled = 1; | ||
1250 | |||
1251 | if(eth16i_debug > 3) | ||
1252 | printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status); | ||
1253 | |||
1254 | if( status & 0x7f00 ) { | ||
1255 | |||
1256 | lp->stats.rx_errors++; | ||
1257 | |||
1258 | if(status & (BUS_RD_ERR << 8) ) | ||
1259 | printk(KERN_WARNING "%s: Bus read error.\n",dev->name); | ||
1260 | if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++; | ||
1261 | if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++; | ||
1262 | if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++; | ||
1263 | if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++; | ||
1264 | } | ||
1265 | if( status & 0x001a) { | ||
1266 | |||
1267 | lp->stats.tx_errors++; | ||
1268 | |||
1269 | if(status & CR_LOST) lp->stats.tx_carrier_errors++; | ||
1270 | if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++; | ||
1271 | |||
1272 | #if 0 | ||
1273 | if(status & COLLISION) { | ||
1274 | lp->stats.collisions += | ||
1275 | ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4); | ||
1276 | } | ||
1277 | #endif | ||
1278 | if(status & COLLISIONS_16) { | ||
1279 | if(lp->col_16 < MAX_COL_16) { | ||
1280 | lp->col_16++; | ||
1281 | lp->stats.collisions++; | ||
1282 | /* Resume transmitting, skip failed packet */ | ||
1283 | outb(0x02, ioaddr + COL_16_REG); | ||
1284 | } | ||
1285 | else { | ||
1286 | printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name); | ||
1287 | } | ||
1288 | } | ||
1289 | } | ||
1290 | |||
1291 | if( status & 0x00ff ) { /* Let's check the transmit status reg */ | ||
1292 | |||
1293 | if(status & TX_DONE) { /* The transmit has been done */ | ||
1294 | lp->stats.tx_packets = lp->tx_buffered_packets; | ||
1295 | lp->stats.tx_bytes += lp->tx_buffered_bytes; | ||
1296 | lp->col_16 = 0; | ||
1297 | |||
1298 | if(lp->tx_queue) { /* Is there still packets ? */ | ||
1299 | /* There was packet(s) so start transmitting and write also | ||
1300 | how many packets there is to be sended */ | ||
1301 | outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG); | ||
1302 | lp->tx_queue = 0; | ||
1303 | lp->tx_queue_len = 0; | ||
1304 | lp->tx_started = 1; | ||
1305 | } | ||
1306 | else { | ||
1307 | lp->tx_started = 0; | ||
1308 | } | ||
1309 | netif_wake_queue(dev); | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | if( ( status & 0x8000 ) || | ||
1314 | ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) { | ||
1315 | eth16i_rx(dev); /* We have packet in receive buffer */ | ||
1316 | } | ||
1317 | |||
1318 | /* Turn interrupts back on */ | ||
1319 | outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); | ||
1320 | |||
1321 | if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { | ||
1322 | /* There is still more room for one more packet in tx buffer */ | ||
1323 | netif_wake_queue(dev); | ||
1324 | } | ||
1325 | |||
1326 | spin_unlock(&lp->lock); | ||
1327 | |||
1328 | return IRQ_RETVAL(handled); | ||
1329 | } | ||
1330 | |||
1331 | static void eth16i_skip_packet(struct net_device *dev) | ||
1332 | { | ||
1333 | int ioaddr = dev->base_addr; | ||
1334 | |||
1335 | inw(ioaddr + DATAPORT); | ||
1336 | inw(ioaddr + DATAPORT); | ||
1337 | inw(ioaddr + DATAPORT); | ||
1338 | |||
1339 | outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG); | ||
1340 | while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0); | ||
1341 | } | ||
1342 | |||
1343 | static void eth16i_reset(struct net_device *dev) | ||
1344 | { | ||
1345 | struct eth16i_local *lp = netdev_priv(dev); | ||
1346 | int ioaddr = dev->base_addr; | ||
1347 | |||
1348 | if(eth16i_debug > 1) | ||
1349 | printk(KERN_DEBUG "%s: Resetting device.\n", dev->name); | ||
1350 | |||
1351 | BITSET(ioaddr + CONFIG_REG_0, DLC_EN); | ||
1352 | outw(0xffff, ioaddr + TX_STATUS_REG); | ||
1353 | eth16i_select_regbank(2, ioaddr); | ||
1354 | |||
1355 | lp->tx_started = 0; | ||
1356 | lp->tx_buf_busy = 0; | ||
1357 | lp->tx_queue = 0; | ||
1358 | lp->tx_queue_len = 0; | ||
1359 | BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); | ||
1360 | } | ||
1361 | |||
1362 | static void eth16i_multicast(struct net_device *dev) | ||
1363 | { | ||
1364 | int ioaddr = dev->base_addr; | ||
1365 | |||
1366 | if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) | ||
1367 | { | ||
1368 | dev->flags|=IFF_PROMISC; /* Must do this */ | ||
1369 | outb(3, ioaddr + RECEIVE_MODE_REG); | ||
1370 | } else { | ||
1371 | outb(2, ioaddr + RECEIVE_MODE_REG); | ||
1372 | } | ||
1373 | } | ||
1374 | |||
1375 | static struct net_device_stats *eth16i_get_stats(struct net_device *dev) | ||
1376 | { | ||
1377 | struct eth16i_local *lp = netdev_priv(dev); | ||
1378 | return &lp->stats; | ||
1379 | } | ||
1380 | |||
1381 | static void eth16i_select_regbank(unsigned char banknbr, int ioaddr) | ||
1382 | { | ||
1383 | unsigned char data; | ||
1384 | |||
1385 | data = inb(ioaddr + CONFIG_REG_1); | ||
1386 | outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); | ||
1387 | } | ||
1388 | |||
1389 | #ifdef MODULE | ||
1390 | |||
1391 | static ushort eth16i_parse_mediatype(const char* s) | ||
1392 | { | ||
1393 | if(!s) | ||
1394 | return E_PORT_FROM_EPROM; | ||
1395 | |||
1396 | if (!strncmp(s, "bnc", 3)) | ||
1397 | return E_PORT_BNC; | ||
1398 | else if (!strncmp(s, "tp", 2)) | ||
1399 | return E_PORT_TP; | ||
1400 | else if (!strncmp(s, "dix", 3)) | ||
1401 | return E_PORT_DIX; | ||
1402 | else if (!strncmp(s, "auto", 4)) | ||
1403 | return E_PORT_AUTO; | ||
1404 | else | ||
1405 | return E_PORT_FROM_EPROM; | ||
1406 | } | ||
1407 | |||
1408 | #define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */ | ||
1409 | |||
1410 | static struct net_device *dev_eth16i[MAX_ETH16I_CARDS]; | ||
1411 | static int io[MAX_ETH16I_CARDS]; | ||
1412 | #if 0 | ||
1413 | static int irq[MAX_ETH16I_CARDS]; | ||
1414 | #endif | ||
1415 | static char* mediatype[MAX_ETH16I_CARDS]; | ||
1416 | static int debug = -1; | ||
1417 | |||
1418 | MODULE_AUTHOR("Mika Kuoppala <miku@iki.fi>"); | ||
1419 | MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver"); | ||
1420 | MODULE_LICENSE("GPL"); | ||
1421 | |||
1422 | |||
1423 | module_param_array(io, int, NULL, 0); | ||
1424 | MODULE_PARM_DESC(io, "eth16i I/O base address(es)"); | ||
1425 | |||
1426 | #if 0 | ||
1427 | module_param_array(irq, int, NULL, 0); | ||
1428 | MODULE_PARM_DESC(irq, "eth16i interrupt request number"); | ||
1429 | #endif | ||
1430 | |||
1431 | module_param_array(mediatype, charp, NULL, 0); | ||
1432 | MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,eprom)"); | ||
1433 | |||
1434 | module_param(debug, int, 0); | ||
1435 | MODULE_PARM_DESC(debug, "eth16i debug level (0-6)"); | ||
1436 | |||
1437 | int init_module(void) | ||
1438 | { | ||
1439 | int this_dev, found = 0; | ||
1440 | struct net_device *dev; | ||
1441 | |||
1442 | for (this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { | ||
1443 | dev = alloc_etherdev(sizeof(struct eth16i_local)); | ||
1444 | if (!dev) | ||
1445 | break; | ||
1446 | |||
1447 | dev->base_addr = io[this_dev]; | ||
1448 | |||
1449 | if(debug != -1) | ||
1450 | eth16i_debug = debug; | ||
1451 | |||
1452 | if(eth16i_debug > 1) | ||
1453 | printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" ); | ||
1454 | |||
1455 | dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); | ||
1456 | |||
1457 | if(io[this_dev] == 0) { | ||
1458 | if(this_dev != 0) /* Only autoprobe 1st one */ | ||
1459 | break; | ||
1460 | |||
1461 | printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n"); | ||
1462 | } | ||
1463 | |||
1464 | if (do_eth16i_probe(dev) == 0) { | ||
1465 | if (register_netdev(dev) == 0) { | ||
1466 | dev_eth16i[found++] = dev; | ||
1467 | continue; | ||
1468 | } | ||
1469 | free_irq(dev->irq, dev); | ||
1470 | release_region(dev->base_addr, ETH16I_IO_EXTENT); | ||
1471 | } | ||
1472 | printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", | ||
1473 | io[this_dev]); | ||
1474 | free_netdev(dev); | ||
1475 | break; | ||
1476 | } | ||
1477 | if (found) | ||
1478 | return 0; | ||
1479 | return -ENXIO; | ||
1480 | } | ||
1481 | |||
1482 | void cleanup_module(void) | ||
1483 | { | ||
1484 | int this_dev; | ||
1485 | |||
1486 | for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { | ||
1487 | struct net_device *dev = dev_eth16i[this_dev]; | ||
1488 | |||
1489 | if(dev->priv) { | ||
1490 | unregister_netdev(dev); | ||
1491 | free_irq(dev->irq, dev); | ||
1492 | release_region(dev->base_addr, ETH16I_IO_EXTENT); | ||
1493 | free_netdev(dev); | ||
1494 | } | ||
1495 | } | ||
1496 | } | ||
1497 | #endif /* MODULE */ | ||
1498 | |||
1499 | /* | ||
1500 | * Local variables: | ||
1501 | * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c" | ||
1502 | * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c" | ||
1503 | * tab-width: 8 | ||
1504 | * c-basic-offset: 8 | ||
1505 | * c-indent-level: 8 | ||
1506 | * End: | ||
1507 | */ | ||
1508 | |||
1509 | /* End of file eth16i.c */ | ||