Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2  * Linux ARCnet driver - COM20020 PCMCIA support
  3  * 
  4  * Written 1994-1999 by Avery Pennarun,
  5  *    based on an ISA version by David Woodhouse.
  6  * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
  7  *    which was derived from pcnet_cs.c by David Hinds.
  8  * Some additional portions derived from skeleton.c by Donald Becker.
  9  *
 10  * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
 11  *  for sponsoring the further development of this driver.
 12  *
 13  * **********************
 14  *
 15  * The original copyright of skeleton.c was as follows:
 16  *
 17  * skeleton.c Written 1993 by Donald Becker.
 18  * Copyright 1993 United States Government as represented by the
 19  * Director, National Security Agency.  This software may only be used
 20  * and distributed according to the terms of the GNU General Public License as
 21  * modified by SRC, incorporated herein by reference.
 22  * 
 23  * **********************
 24  * Changes:
 25  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
 26  * - reorganize kmallocs in com20020_attach, checking all for failure
 27  *   and releasing the previous allocations if one fails
 28  * **********************
 29  * 
 30  * For more details, see drivers/net/arcnet.c
 31  *
 32  * **********************
 33  */
 34 #include <linux/kernel.h>
 35 #include <linux/init.h>
 36 #include <linux/ptrace.h>
 37 #include <linux/slab.h>
 38 #include <linux/string.h>
 39 #include <linux/timer.h>
 40 #include <linux/delay.h>
 41 #include <linux/module.h>
 42 #include <linux/netdevice.h>
 43 #include <linux/arcdevice.h>
 44 #include <linux/com20020.h>
 45 
 46 #include <pcmcia/cs_types.h>
 47 #include <pcmcia/cs.h>
 48 #include <pcmcia/cistpl.h>
 49 #include <pcmcia/ds.h>
 50 
 51 #include <asm/io.h>
 52 #include <asm/system.h>
 53 
 54 #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
 55 
 56 #ifdef PCMCIA_DEBUG
 57 
 58 static int pc_debug = PCMCIA_DEBUG;
 59 module_param(pc_debug, int, 0);
 60 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 61 
 62 static void regdump(struct net_device *dev)
 63 {
 64     int ioaddr = dev->base_addr;
 65     int count;
 66     
 67     printk("com20020 register dump:\n");
 68     for (count = ioaddr; count < ioaddr + 16; count++)
 69     {
 70         if (!(count % 16))
 71             printk("\n%04X: ", count);
 72         printk("%02X ", inb(count));
 73     }
 74     printk("\n");
 75     
 76     printk("buffer0 dump:\n");
 77         /* set up the address register */
 78         count = 0;
 79         outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
 80         outb(count & 0xff, _ADDR_LO);
 81     
 82     for (count = 0; count < 256+32; count++)
 83     {
 84         if (!(count % 16))
 85             printk("\n%04X: ", count);
 86         
 87         /* copy the data */
 88         printk("%02X ", inb(_MEMDATA));
 89     }
 90     printk("\n");
 91 }
 92 
 93 #else
 94 
 95 #define DEBUG(n, args...) do { } while (0)
 96 static inline void regdump(struct net_device *dev) { }
 97 
 98 #endif
 99 
100 
101 /*====================================================================*/
102 
103 /* Parameters that can be set with 'insmod' */
104 
105 static int node;
106 static int timeout = 3;
107 static int backplane;
108 static int clockp;
109 static int clockm;
110 
111 module_param(node, int, 0);
112 module_param(timeout, int, 0);
113 module_param(backplane, int, 0);
114 module_param(clockp, int, 0);
115 module_param(clockm, int, 0);
116 
117 MODULE_LICENSE("GPL");
118 
119 /*====================================================================*/
120 
121 static int com20020_config(struct pcmcia_device *link);
122 static void com20020_release(struct pcmcia_device *link);
123 
124 static void com20020_detach(struct pcmcia_device *p_dev);
125 
126 /*====================================================================*/
127 
128 typedef struct com20020_dev_t {
129     struct net_device       *dev;
130     dev_node_t          node;
131 } com20020_dev_t;
132 
133 /*======================================================================
134 
135     com20020_attach() creates an "instance" of the driver, allocating
136     local data structures for one device.  The device is registered
137     with Card Services.
138 
139 ======================================================================*/
140 
141 static int com20020_probe(struct pcmcia_device *p_dev)
142 {
143     com20020_dev_t *info;
144     struct net_device *dev;
145     struct arcnet_local *lp;
146 
147     DEBUG(0, "com20020_attach()\n");
148 
149     /* Create new network device */
150     info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
151     if (!info)
152         goto fail_alloc_info;
153 
154     dev = alloc_arcdev("");
155     if (!dev)
156         goto fail_alloc_dev;
157 
158     lp = netdev_priv(dev);
159     lp->timeout = timeout;
160     lp->backplane = backplane;
161     lp->clockp = clockp;
162     lp->clockm = clockm & 3;
163     lp->hw.owner = THIS_MODULE;
164 
165     /* fill in our module parameters as defaults */
166     dev->dev_addr[0] = node;
167 
168     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
169     p_dev->io.NumPorts1 = 16;
170     p_dev->io.IOAddrLines = 16;
171     p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
172     p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
173     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
174     p_dev->conf.IntType = INT_MEMORY_AND_IO;
175 
176     p_dev->irq.Instance = info->dev = dev;
177     p_dev->priv = info;
178 
179     return com20020_config(p_dev);
180 
181 fail_alloc_dev:
182     kfree(info);
183 fail_alloc_info:
184     return -ENOMEM;
185 } /* com20020_attach */
186 
187 /*======================================================================
188 
189     This deletes a driver "instance".  The device is de-registered
190     with Card Services.  If it has been released, all local data
191     structures are freed.  Otherwise, the structures will be freed
192     when the device is released.
193 
194 ======================================================================*/
195 
196 static void com20020_detach(struct pcmcia_device *link)
197 {
198     struct com20020_dev_t *info = link->priv;
199     struct net_device *dev = info->dev;
200 
201     DEBUG(1,"detach...\n");
202 
203     DEBUG(0, "com20020_detach(0x%p)\n", link);
204 
205     if (link->dev_node) {
206         DEBUG(1,"unregister...\n");
207 
208         unregister_netdev(dev);
209 
210         /*
211          * this is necessary because we register our IRQ separately
212          * from card services.
213          */
214         if (dev->irq)
215             free_irq(dev->irq, dev);
216     }
217 
218     com20020_release(link);
219 
220     /* Unlink device structure, free bits */
221     DEBUG(1,"unlinking...\n");
222     if (link->priv)
223     {
224         dev = info->dev;
225         if (dev)
226         {
227             DEBUG(1,"kfree...\n");
228             free_netdev(dev);
229         }
230         DEBUG(1,"kfree2...\n");
231         kfree(info);
232     }
233 
234 } /* com20020_detach */
235 
236 /*======================================================================
237 
238     com20020_config() is scheduled to run after a CARD_INSERTION event
239     is received, to configure the PCMCIA socket, and to make the
240     device available to the system.
241 
242 ======================================================================*/
243 
244 #define CS_CHECK(fn, ret) \
245 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
246 
247 static int com20020_config(struct pcmcia_device *link)
248 {
249     struct arcnet_local *lp;
250     com20020_dev_t *info;
251     struct net_device *dev;
252     int i, last_ret, last_fn;
253     int ioaddr;
254 
255     info = link->priv;
256     dev = info->dev;
257 
258     DEBUG(1,"config...\n");
259 
260     DEBUG(0, "com20020_config(0x%p)\n", link);
261 
262     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
263     i = -ENODEV;
264     if (!link->io.BasePort1)
265     {
266         for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
267         {
268             link->io.BasePort1 = ioaddr;
269             i = pcmcia_request_io(link, &link->io);
270             if (i == 0)
271                 break;
272         }
273     }
274     else
275         i = pcmcia_request_io(link, &link->io);
276     
277     if (i != 0)
278     {
279         DEBUG(1,"arcnet: requestIO failed totally!\n");
280         goto failed;
281     }
282         
283     ioaddr = dev->base_addr = link->io.BasePort1;
284     DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr);
285 
286     DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
287            link->irq.AssignedIRQ,
288            link->irq.IRQInfo1, link->irq.IRQInfo2);
289     i = pcmcia_request_irq(link, &link->irq);
290     if (i != 0)
291     {
292         DEBUG(1,"arcnet: requestIRQ failed totally!\n");
293         goto failed;
294     }
295 
296     dev->irq = link->irq.AssignedIRQ;
297 
298     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
299 
300     if (com20020_check(dev))
301     {
302         regdump(dev);
303         goto failed;
304     }
305     
306     lp = netdev_priv(dev);
307     lp->card_name = "PCMCIA COM20020";
308     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
309 
310     link->dev_node = &info->node;
311     SET_NETDEV_DEV(dev, &handle_to_dev(link));
312 
313     i = com20020_found(dev, 0); /* calls register_netdev */
314     
315     if (i != 0) {
316         DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
317         link->dev_node = NULL;
318         goto failed;
319     }
320 
321     strcpy(info->node.dev_name, dev->name);
322 
323     DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
324            dev->name, dev->base_addr, dev->irq);
325     return 0;
326 
327 cs_failed:
328     cs_error(link, last_fn, last_ret);
329 failed:
330     DEBUG(1,"com20020_config failed...\n");
331     com20020_release(link);
332     return -ENODEV;
333 } /* com20020_config */
334 
335 /*======================================================================
336 
337     After a card is removed, com20020_release() will unregister the net
338     device, and release the PCMCIA configuration.  If the device is
339     still open, this will be postponed until it is closed.
340 
341 ======================================================================*/
342 
343 static void com20020_release(struct pcmcia_device *link)
344 {
345         DEBUG(0, "com20020_release(0x%p)\n", link);
346         pcmcia_disable_device(link);
347 }
348 
349 static int com20020_suspend(struct pcmcia_device *link)
350 {
351         com20020_dev_t *info = link->priv;
352         struct net_device *dev = info->dev;
353 
354         if (link->open)
355                 netif_device_detach(dev);
356 
357         return 0;
358 }
359 
360 static int com20020_resume(struct pcmcia_device *link)
361 {
362         com20020_dev_t *info = link->priv;
363         struct net_device *dev = info->dev;
364 
365         if (link->open) {
366                 int ioaddr = dev->base_addr;
367                 struct arcnet_local *lp = netdev_priv(dev);
368                 ARCRESET;
369         }
370 
371         return 0;
372 }
373 
374 static struct pcmcia_device_id com20020_ids[] = {
375         PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
376                         "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
377         PCMCIA_DEVICE_PROD_ID12("SoHard AG",
378                         "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
379         PCMCIA_DEVICE_NULL
380 };
381 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
382 
383 static struct pcmcia_driver com20020_cs_driver = {
384         .owner          = THIS_MODULE,
385         .drv            = {
386                 .name   = "com20020_cs",
387         },
388         .probe          = com20020_probe,
389         .remove         = com20020_detach,
390         .id_table       = com20020_ids,
391         .suspend        = com20020_suspend,
392         .resume         = com20020_resume,
393 };
394 
395 static int __init init_com20020_cs(void)
396 {
397         return pcmcia_register_driver(&com20020_cs_driver);
398 }
399 
400 static void __exit exit_com20020_cs(void)
401 {
402         pcmcia_unregister_driver(&com20020_cs_driver);
403 }
404 
405 module_init(init_com20020_cs);
406 module_exit(exit_com20020_cs);
407 
  This page was automatically generated by the LXR engine.