~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/net/mac89x0.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* cs89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */
  2 /*
  3         Written 1996 by Russell Nelson, with reference to skeleton.c
  4         written 1993-1994 by Donald Becker.
  5 
  6         This software may be used and distributed according to the terms
  7         of the GNU Public License, incorporated herein by reference.
  8 
  9         The author may be reached at nelson@crynwr.com, Crynwr
 10         Software, 11 Grant St., Potsdam, NY 13676
 11 
 12   Changelog:
 13 
 14   Mike Cruse        : mcruse@cti-ltd.com
 15                     : Changes for Linux 2.0 compatibility. 
 16                     : Added dev_id parameter in net_interrupt(),
 17                     : request_irq() and free_irq(). Just NULL for now.
 18 
 19   Mike Cruse        : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
 20                     : in net_open() and net_close() so kerneld would know
 21                     : that the module is in use and wouldn't eject the 
 22                     : driver prematurely.
 23 
 24   Mike Cruse        : Rewrote init_module() and cleanup_module using 8390.c
 25                     : as an example. Disabled autoprobing in init_module(),
 26                     : not a good thing to do to other devices while Linux
 27                     : is running from all accounts.
 28                     
 29   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
 30 
 31   David Huggins-Daines <dhd@debian.org>
 32   
 33   Split this off into mac89x0.c, and gutted it of all parts which are
 34   not relevant to the existing CS8900 cards on the Macintosh
 35   (i.e. basically the Daynaport CS and LC cards).  To be precise:
 36 
 37     * Removed all the media-detection stuff, because these cards are
 38     TP-only.
 39 
 40     * Lobotomized the ISA interrupt bogosity, because these cards use
 41     a hardwired NuBus interrupt and a magic ISAIRQ value in the card.
 42 
 43     * Basically eliminated everything not relevant to getting the
 44     cards minimally functioning on the Macintosh.
 45 
 46   I might add that these cards are badly designed even from the Mac
 47   standpoint, in that Dayna, in their infinite wisdom, used NuBus slot
 48   I/O space and NuBus interrupts for these cards, but neglected to
 49   provide anything even remotely resembling a NuBus ROM.  Therefore we
 50   have to probe for them in a brain-damaged ISA-like fashion.
 51 */
 52 
 53 static char *version =
 54 "cs89x0.c:v1.02 11/26/96 Russell Nelson <nelson@crynwr.com>\n";
 55 
 56 /* ======================= configure the driver here ======================= */
 57 
 58 /* use 0 for production, 1 for verification, >2 for debug */
 59 #ifndef NET_DEBUG
 60 #define NET_DEBUG 0
 61 #endif
 62 
 63 /* ======================= end of configuration ======================= */
 64 
 65 
 66 /* Always include 'config.h' first in case the user wants to turn on
 67    or override something. */
 68 #include <linux/module.h>
 69 
 70 #define PRINTK(x) printk x
 71 
 72 /*
 73   Sources:
 74 
 75         Crynwr packet driver epktisa.
 76 
 77         Crystal Semiconductor data sheets.
 78 
 79 */
 80 
 81 #include <linux/kernel.h>
 82 #include <linux/sched.h>
 83 #include <linux/types.h>
 84 #include <linux/fcntl.h>
 85 #include <linux/interrupt.h>
 86 #include <linux/ptrace.h>
 87 #include <linux/ioport.h>
 88 #include <linux/in.h>
 89 #include <linux/malloc.h>
 90 #include <linux/string.h>
 91 #include <linux/nubus.h>
 92 #include <asm/system.h>
 93 #include <asm/bitops.h>
 94 #include <asm/io.h>
 95 #include <asm/hwtest.h>
 96 #include <asm/macints.h>
 97 #include <linux/errno.h>
 98 #include <linux/init.h>
 99 
100 #include <linux/netdevice.h>
101 #include <linux/etherdevice.h>
102 #include <linux/skbuff.h>
103 #include "cs89x0.h"
104 
105 static unsigned int net_debug = NET_DEBUG;
106 
107 /* Information that need to be kept for each board. */
108 struct net_local {
109         struct net_device_stats stats;
110         int chip_type;          /* one of: CS8900, CS8920, CS8920M */
111         char chip_revision;     /* revision letter of the chip ('A'...) */
112         int send_cmd;           /* the propercommand used to send a packet. */
113         int rx_mode;
114         int curr_rx_cfg;
115         int send_underrun;      /* keep track of how many underruns in a row we get */
116         struct sk_buff *skb;
117 };
118 
119 /* Index to functions, as function prototypes. */
120 
121 extern int mac89x0_probe(struct net_device *dev);
122 #if 0
123 extern void reset_chip(struct net_device *dev);
124 #endif
125 static int net_open(struct net_device *dev);
126 static int      net_send_packet(struct sk_buff *skb, struct net_device *dev);
127 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
128 static void set_multicast_list(struct net_device *dev);
129 static void net_rx(struct net_device *dev);
130 static int net_close(struct net_device *dev);
131 static struct net_device_stats *net_get_stats(struct net_device *dev);
132 static int set_mac_address(struct net_device *dev, void *addr);
133 
134 
135 /* Example routines you must write ;->. */
136 #define tx_done(dev) 1
137 
138 /* For reading/writing registers ISA-style */
139 static int inline
140 readreg_io(struct net_device *dev, int portno)
141 {
142         writew(swab16(portno), dev->base_addr + ADD_PORT);
143         return swab16(readw(dev->base_addr + DATA_PORT));
144 }
145 
146 static void inline
147 writereg_io(struct net_device *dev, int portno, int value)
148 {
149         writew(swab16(portno), dev->base_addr + ADD_PORT);
150         writew(swab16(value), dev->base_addr + DATA_PORT);
151 }
152 
153 /* These are for reading/writing registers in shared memory */
154 static int inline
155 readreg(struct net_device *dev, int portno)
156 {
157         return swab16(readw(dev->mem_start + portno));
158 }
159 
160 static void inline
161 writereg(struct net_device *dev, int portno, int value)
162 {
163         writew(swab16(value), dev->mem_start + portno);
164 }
165 
166 /* Probe for the CS8900 card in slot E.  We won't bother looking
167    anywhere else until we have a really good reason to do so. */
168 int __init mac89x0_probe(struct net_device *dev)
169 {
170         static int once_is_enough = 0;
171         struct net_local *lp;
172         static unsigned version_printed = 0;
173         int i, slot;
174         unsigned rev_type = 0;
175         unsigned long ioaddr;
176         unsigned short sig;
177 
178         SET_MODULE_OWNER(dev);
179 
180         if (once_is_enough)
181                 return -ENODEV;
182         once_is_enough = 1;
183 
184         /* We might have to parameterize this later */
185         slot = 0xE;
186         /* Get out now if there's a real NuBus card in slot E */
187         if (nubus_find_slot(slot, NULL) != NULL)
188                 return -ENODEV; 
189 
190         /* The pseudo-ISA bits always live at offset 0x300 (gee,
191            wonder why...) */
192         ioaddr = (unsigned long)
193                 nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE);
194         {
195                 unsigned long flags;
196                 int card_present;
197                 
198                 save_flags(flags);
199                 cli();
200                 card_present = hwreg_present((void*) ioaddr+4)
201                   && hwreg_present((void*) ioaddr + DATA_PORT);
202                 restore_flags(flags);
203 
204                 if (!card_present)
205                         return -ENODEV;
206         }
207 
208         writew(0, ioaddr + ADD_PORT);
209         sig = readw(ioaddr + DATA_PORT);
210         if (sig != swab16(CHIP_EISA_ID_SIG))
211                 return -ENODEV;
212 
213         /* Initialize the net_device structure. */
214         if (dev->priv == NULL) {
215                 dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
216                 memset(dev->priv, 0, sizeof(struct net_local));
217         }
218         lp = (struct net_local *)dev->priv;
219 
220         /* Fill in the 'dev' fields. */
221         dev->base_addr = ioaddr;
222         dev->mem_start = (unsigned long) 
223                 nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
224         dev->mem_end = dev->mem_start + 0x1000;
225 
226         /* Turn on shared memory */
227         writereg_io(dev, PP_BusCTL, MEMORY_ON);
228 
229         /* get the chip type */
230         rev_type = readreg(dev, PRODUCT_ID_ADD);
231         lp->chip_type = rev_type &~ REVISON_BITS;
232         lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A';
233 
234         /* Check the chip type and revision in order to set the correct send command
235         CS8920 revision C and CS8900 revision F can use the faster send. */
236         lp->send_cmd = TX_AFTER_381;
237         if (lp->chip_type == CS8900 && lp->chip_revision >= 'F')
238                 lp->send_cmd = TX_NOW;
239         if (lp->chip_type != CS8900 && lp->chip_revision >= 'C')
240                 lp->send_cmd = TX_NOW;
241 
242         if (net_debug && version_printed++ == 0)
243                 printk(version);
244 
245         printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx",
246                dev->name,
247                lp->chip_type==CS8900?'':'2',
248                lp->chip_type==CS8920M?"M":"",
249                lp->chip_revision,
250                dev->base_addr);
251 
252         /* Try to read the MAC address */
253         if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) {
254                 printk("\nmac89x0: No EEPROM, giving up now.\n");
255                 return -ENODEV;
256         } else {
257                 for (i = 0; i < ETH_ALEN; i += 2) {
258                         /* Big-endian (why??!) */
259                         unsigned short s = readreg(dev, PP_IA + i);
260                         dev->dev_addr[i] = s >> 8;
261                         dev->dev_addr[i+1] = s & 0xff;
262                 }
263         }
264 
265         dev->irq = SLOT2IRQ(slot);
266         printk(" IRQ %d ADDR ", dev->irq);
267 
268         /* print the ethernet address. */
269         for (i = 0; i < ETH_ALEN; i++)
270                 printk("%2.2x%s", dev->dev_addr[i],
271                        ((i < ETH_ALEN-1) ? ":" : ""));
272 
273         dev->open               = net_open;
274         dev->stop               = net_close;
275         dev->hard_start_xmit = net_send_packet;
276         dev->get_stats  = net_get_stats;
277         dev->set_multicast_list = &set_multicast_list;
278         dev->set_mac_address = &set_mac_address;
279 
280         /* Fill in the fields of the net_device structure with ethernet values. */
281         ether_setup(dev);
282 
283         printk("\n");
284         return 0;
285 }
286 
287 #if 0
288 /* This is useful for something, but I don't know what yet. */
289 void __init reset_chip(struct net_device *dev)
290 {
291         int reset_start_time;
292 
293         writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
294 
295         /* wait 30 ms */
296         current->state = TASK_INTERRUPTIBLE;
297         schedule_timeout(30*HZ/1000);
298 
299         /* Wait until the chip is reset */
300         reset_start_time = jiffies;
301         while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
302                 ;
303 }
304 #endif
305 
306 /* Open/initialize the board.  This is called (in the current kernel)
307    sometime after booting when the 'ifconfig' program is run.
308 
309    This routine should set everything up anew at each open, even
310    registers that "should" only need to be set once at boot, so that
311    there is non-reboot way to recover if something goes wrong.
312    */
313 static int
314 net_open(struct net_device *dev)
315 {
316         struct net_local *lp = (struct net_local *)dev->priv;
317         int i;
318 
319         /* Disable the interrupt for now */
320         writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ);
321 
322         /* Grab the interrupt */
323         if (request_irq(dev->irq, &net_interrupt, 0, "cs89x0", dev))
324                 return -EAGAIN;
325 
326         /* Set up the IRQ - Apparently magic */
327         if (lp->chip_type == CS8900)
328                 writereg(dev, PP_CS8900_ISAINT, 0);
329         else
330                 writereg(dev, PP_CS8920_ISAINT, 0);
331 
332         /* set the Ethernet address */
333         for (i=0; i < ETH_ALEN/2; i++)
334                 writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
335 
336         /* Turn on both receive and transmit operations */
337         writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON);
338 
339         /* Receive only error free packets addressed to this card */
340         lp->rx_mode = 0;
341         writereg(dev, PP_RxCTL, DEF_RX_ACCEPT);
342 
343         lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL;
344 
345         writereg(dev, PP_RxCFG, lp->curr_rx_cfg);
346 
347         writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL |
348                TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL);
349 
350         writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL |
351                  TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL);
352 
353         /* now that we've got our act together, enable everything */
354         writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ);
355         netif_start_queue(dev);
356         return 0;
357 }
358 
359 static int
360 net_send_packet(struct sk_buff *skb, struct net_device *dev)
361 {
362         if (dev->tbusy) {
363                 /* If we get here, some higher level has decided we are broken.
364                    There should really be a "kick me" function call instead. */
365                 int tickssofar = jiffies - dev->trans_start;
366                 if (tickssofar < 5)
367                         return 1;
368                 if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
369                            tx_done(dev) ? "IRQ conflict" : "network cable problem");
370                 /* Try to restart the adaptor. */
371                 dev->tbusy=0;
372                 dev->trans_start = jiffies;
373         }
374 
375         /* Block a timer-based transmit from overlapping.  This could better be
376            done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
377         if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
378                 printk("%s: Transmitter access conflict.\n", dev->name);
379         else {
380                 struct net_local *lp = (struct net_local *)dev->priv;
381                 unsigned long flags;
382 
383                 if (net_debug > 3)
384                         printk("%s: sent %d byte packet of type %x\n",
385                                dev->name, skb->len,
386                                (skb->data[ETH_ALEN+ETH_ALEN] << 8)
387                                | skb->data[ETH_ALEN+ETH_ALEN+1]);
388 
389                 /* keep the upload from being interrupted, since we
390                    ask the chip to start transmitting before the
391                    whole packet has been completely uploaded. */
392                 save_flags(flags);
393                 cli();
394 
395                 /* initiate a transmit sequence */
396                 writereg(dev, PP_TxCMD, lp->send_cmd);
397                 writereg(dev, PP_TxLength, skb->len);
398 
399                 /* Test to see if the chip has allocated memory for the packet */
400                 if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
401                         /* Gasp!  It hasn't.  But that shouldn't happen since
402                            we're waiting for TxOk, so return 1 and requeue this packet. */
403                         restore_flags(flags);
404                         return 1;
405                 }
406 
407                 /* Write the contents of the packet */
408                 memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
409 
410                 restore_flags(flags);
411                 dev->trans_start = jiffies;
412         }
413         dev_kfree_skb (skb);
414 
415         return 0;
416 }
417 
418 /* The typical workload of the driver:
419    Handle the network interface interrupts. */
420 static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
421 {
422         struct net_device *dev = dev_id;
423         struct net_local *lp;
424         int ioaddr, status;
425 
426         if (dev == NULL) {
427                 printk ("net_interrupt(): irq %d for unknown device.\n", irq);
428                 return;
429         }
430         if (dev->interrupt)
431                 printk("%s: Re-entering the interrupt handler.\n", dev->name);
432         dev->interrupt = 1;
433 
434         ioaddr = dev->base_addr;
435         lp = (struct net_local *)dev->priv;
436 
437         /* we MUST read all the events out of the ISQ, otherwise we'll never
438            get interrupted again.  As a consequence, we can't have any limit
439            on the number of times we loop in the interrupt handler.  The
440            hardware guarantees that eventually we'll run out of events.  Of
441            course, if you're on a slow machine, and packets are arriving
442            faster than you can read them off, you're screwed.  Hasta la
443            vista, baby!  */
444         while ((status = swab16(readw(dev->base_addr + ISQ_PORT)))) {
445                 if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status);
446                 switch(status & ISQ_EVENT_MASK) {
447                 case ISQ_RECEIVER_EVENT:
448                         /* Got a packet(s). */
449                         net_rx(dev);
450                         break;
451                 case ISQ_TRANSMITTER_EVENT:
452                         lp->stats.tx_packets++;
453                         dev->tbusy = 0;
454                         mark_bh(NET_BH);        /* Inform upper layers. */
455                         if ((status & TX_OK) == 0) lp->stats.tx_errors++;
456                         if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
457                         if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
458                         if (status & TX_LATE_COL) lp->stats.tx_window_errors++;
459                         if (status & TX_16_COL) lp->stats.tx_aborted_errors++;
460                         break;
461                 case ISQ_BUFFER_EVENT:
462                         if (status & READY_FOR_TX) {
463                                 /* we tried to transmit a packet earlier,
464                                    but inexplicably ran out of buffers.
465                                    That shouldn't happen since we only ever
466                                    load one packet.  Shrug.  Do the right
467                                    thing anyway. */
468                                 dev->tbusy = 0;
469                                 mark_bh(NET_BH);        /* Inform upper layers. */
470                         }
471                         if (status & TX_UNDERRUN) {
472                                 if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
473                                 lp->send_underrun++;
474                                 if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381;
475                                 else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL;
476                         }
477                         break;
478                 case ISQ_RX_MISS_EVENT:
479                         lp->stats.rx_missed_errors += (status >>6);
480                         break;
481                 case ISQ_TX_COL_EVENT:
482                         lp->stats.collisions += (status >>6);
483                         break;
484                 }
485         }
486         dev->interrupt = 0;
487         return;
488 }
489 
490 /* We have a good packet(s), get it/them out of the buffers. */
491 static void
492 net_rx(struct net_device *dev)
493 {
494         struct net_local *lp = (struct net_local *)dev->priv;
495         struct sk_buff *skb;
496         int status, length;
497 
498         status = readreg(dev, PP_RxStatus);
499         if ((status & RX_OK) == 0) {
500                 lp->stats.rx_errors++;
501                 if (status & RX_RUNT) lp->stats.rx_length_errors++;
502                 if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++;
503                 if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT)))
504                         /* per str 172 */
505                         lp->stats.rx_crc_errors++;
506                 if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
507                 return;
508         }
509 
510         length = readreg(dev, PP_RxLength);
511         /* Malloc up new buffer. */
512         skb = alloc_skb(length, GFP_ATOMIC);
513         if (skb == NULL) {
514                 printk("%s: Memory squeeze, dropping packet.\n", dev->name);
515                 lp->stats.rx_dropped++;
516                 return;
517         }
518         skb->len = length;
519         skb->dev = dev;
520 
521         memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
522 
523         if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
524                                  dev->name, length,
525                                  (skb->data[ETH_ALEN+ETH_ALEN] << 8)
526                                  | skb->data[ETH_ALEN+ETH_ALEN+1]);
527 
528         skb->protocol=eth_type_trans(skb,dev);
529         netif_rx(skb);
530         lp->stats.rx_packets++;
531         lp->stats.rx_bytes+=skb->len;
532         return;
533 }
534 
535 /* The inverse routine to net_open(). */
536 static int
537 net_close(struct net_device *dev)
538 {
539 
540         writereg(dev, PP_RxCFG, 0);
541         writereg(dev, PP_TxCFG, 0);
542         writereg(dev, PP_BufCFG, 0);
543         writereg(dev, PP_BusCTL, 0);
544 
545         netif_stop_queue(dev);
546 
547         free_irq(dev->irq, dev);
548 
549         /* Update the statistics here. */
550 
551         return 0;
552 
553 }
554 
555 /* Get the current statistics.  This may be called with the card open or
556    closed. */
557 static struct net_device_stats *
558 net_get_stats(struct net_device *dev)
559 {
560         struct net_local *lp = (struct net_local *)dev->priv;
561 
562         cli();
563         /* Update the statistics from the device registers. */
564         lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6);
565         lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6);
566         sti();
567 
568         return &lp->stats;
569 }
570 
571 static void set_multicast_list(struct net_device *dev)
572 {
573         struct net_local *lp = (struct net_local *)dev->priv;
574 
575         if(dev->flags&IFF_PROMISC)
576         {
577                 lp->rx_mode = RX_ALL_ACCEPT;
578         }
579         else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
580         {
581                 /* The multicast-accept list is initialized to accept-all, and we
582                    rely on higher-level filtering for now. */
583                 lp->rx_mode = RX_MULTCAST_ACCEPT;
584         } 
585         else
586                 lp->rx_mode = 0;
587 
588         writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode);
589 
590         /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */
591         writereg(dev, PP_RxCFG, lp->curr_rx_cfg |
592              (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0));
593 }
594 
595 
596 static int set_mac_address(struct net_device *dev, void *addr)
597 {
598         int i;
599         if (dev->start)
600                 return -EBUSY;
601         printk("%s: Setting MAC address to ", dev->name);
602         for (i = 0; i < 6; i++)
603                 printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
604         printk(".\n");
605         /* set the Ethernet address */
606         for (i=0; i < ETH_ALEN/2; i++)
607                 writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8));
608 
609         return 0;
610 }
611 
612 #ifdef MODULE
613 
614 static struct net_device dev_cs89x0;
615 static int debug;
616 
617 MODULE_PARM(debug, "i");
618 
619 EXPORT_NO_SYMBOLS;
620 
621 int
622 init_module(void)
623 {
624         struct net_local *lp;
625 
626         net_debug = debug;
627         dev_cs89x0.init = mac89x0_probe;
628         dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
629         memset(dev_cs89x0.priv, 0, sizeof(struct net_local));
630         lp = (struct net_local *)dev_cs89x0.priv;
631 
632         if (register_netdev(&dev_cs89x0) != 0) {
633                 printk(KERN_WARNING "mac89x0.c: No card found\n");
634                 return -ENXIO;
635         }
636         return 0;
637 }
638 
639 void
640 cleanup_module(void)
641 {
642 
643 #endif
644 #ifdef MODULE
645         writew(0, dev_cs89x0.base_addr + ADD_PORT);
646 #endif
647 #ifdef MODULE
648 
649         if (dev_cs89x0.priv != NULL) {
650                 /* Free up the private structure, or leak memory :-)  */
651                 unregister_netdev(&dev_cs89x0);
652                 kfree(dev_cs89x0.priv);
653                 dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */
654         }
655 }
656 #endif /* MODULE */
657 
658 /*
659  * Local variables:
660  *  compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o mac89x0.o mac89x0.c"
661  *  version-control: t
662  *  kept-new-versions: 5
663  *  c-indent-level: 8
664  *  tab-width: 8
665  * End:
666  *
667  */
668 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.