Merge ../linux-2.6-watchdog-mm
[linux-2.6] / drivers / net / pcmcia / com20020_cs.c
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 = kmalloc(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     memset(info, 0, sizeof(struct com20020_dev_t));
159     lp = dev->priv;
160     lp->timeout = timeout;
161     lp->backplane = backplane;
162     lp->clockp = clockp;
163     lp->clockm = clockm & 3;
164     lp->hw.owner = THIS_MODULE;
165
166     /* fill in our module parameters as defaults */
167     dev->dev_addr[0] = node;
168
169     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
170     p_dev->io.NumPorts1 = 16;
171     p_dev->io.IOAddrLines = 16;
172     p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
173     p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
174     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
175     p_dev->conf.IntType = INT_MEMORY_AND_IO;
176
177     p_dev->irq.Instance = info->dev = dev;
178     p_dev->priv = info;
179
180     return com20020_config(p_dev);
181
182 fail_alloc_dev:
183     kfree(info);
184 fail_alloc_info:
185     return -ENOMEM;
186 } /* com20020_attach */
187
188 /*======================================================================
189
190     This deletes a driver "instance".  The device is de-registered
191     with Card Services.  If it has been released, all local data
192     structures are freed.  Otherwise, the structures will be freed
193     when the device is released.
194
195 ======================================================================*/
196
197 static void com20020_detach(struct pcmcia_device *link)
198 {
199     struct com20020_dev_t *info = link->priv;
200     struct net_device *dev = info->dev;
201
202     DEBUG(1,"detach...\n");
203
204     DEBUG(0, "com20020_detach(0x%p)\n", link);
205
206     if (link->dev_node) {
207         DEBUG(1,"unregister...\n");
208
209         unregister_netdev(dev);
210
211         /*
212          * this is necessary because we register our IRQ separately
213          * from card services.
214          */
215         if (dev->irq)
216             free_irq(dev->irq, dev);
217     }
218
219     com20020_release(link);
220
221     /* Unlink device structure, free bits */
222     DEBUG(1,"unlinking...\n");
223     if (link->priv)
224     {
225         dev = info->dev;
226         if (dev)
227         {
228             DEBUG(1,"kfree...\n");
229             free_netdev(dev);
230         }
231         DEBUG(1,"kfree2...\n");
232         kfree(info);
233     }
234
235 } /* com20020_detach */
236
237 /*======================================================================
238
239     com20020_config() is scheduled to run after a CARD_INSERTION event
240     is received, to configure the PCMCIA socket, and to make the
241     device available to the system.
242
243 ======================================================================*/
244
245 #define CS_CHECK(fn, ret) \
246 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
247
248 static int com20020_config(struct pcmcia_device *link)
249 {
250     struct arcnet_local *lp;
251     com20020_dev_t *info;
252     struct net_device *dev;
253     int i, last_ret, last_fn;
254     int ioaddr;
255
256     info = link->priv;
257     dev = info->dev;
258
259     DEBUG(1,"config...\n");
260
261     DEBUG(0, "com20020_config(0x%p)\n", link);
262
263     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
264     i = !CS_SUCCESS;
265     if (!link->io.BasePort1)
266     {
267         for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
268         {
269             link->io.BasePort1 = ioaddr;
270             i = pcmcia_request_io(link, &link->io);
271             if (i == CS_SUCCESS)
272                 break;
273         }
274     }
275     else
276         i = pcmcia_request_io(link, &link->io);
277     
278     if (i != CS_SUCCESS)
279     {
280         DEBUG(1,"arcnet: requestIO failed totally!\n");
281         goto failed;
282     }
283         
284     ioaddr = dev->base_addr = link->io.BasePort1;
285     DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr);
286
287     DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
288            link->irq.AssignedIRQ,
289            link->irq.IRQInfo1, link->irq.IRQInfo2);
290     i = pcmcia_request_irq(link, &link->irq);
291     if (i != CS_SUCCESS)
292     {
293         DEBUG(1,"arcnet: requestIRQ failed totally!\n");
294         goto failed;
295     }
296
297     dev->irq = link->irq.AssignedIRQ;
298
299     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
300
301     if (com20020_check(dev))
302     {
303         regdump(dev);
304         goto failed;
305     }
306     
307     lp = dev->priv;
308     lp->card_name = "PCMCIA COM20020";
309     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
310
311     link->dev_node = &info->node;
312     SET_NETDEV_DEV(dev, &handle_to_dev(link));
313
314     i = com20020_found(dev, 0); /* calls register_netdev */
315     
316     if (i != 0) {
317         DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
318         link->dev_node = NULL;
319         goto failed;
320     }
321
322     strcpy(info->node.dev_name, dev->name);
323
324     DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
325            dev->name, dev->base_addr, dev->irq);
326     return 0;
327
328 cs_failed:
329     cs_error(link, last_fn, last_ret);
330 failed:
331     DEBUG(1,"com20020_config failed...\n");
332     com20020_release(link);
333     return -ENODEV;
334 } /* com20020_config */
335
336 /*======================================================================
337
338     After a card is removed, com20020_release() will unregister the net
339     device, and release the PCMCIA configuration.  If the device is
340     still open, this will be postponed until it is closed.
341
342 ======================================================================*/
343
344 static void com20020_release(struct pcmcia_device *link)
345 {
346         DEBUG(0, "com20020_release(0x%p)\n", link);
347         pcmcia_disable_device(link);
348 }
349
350 static int com20020_suspend(struct pcmcia_device *link)
351 {
352         com20020_dev_t *info = link->priv;
353         struct net_device *dev = info->dev;
354
355         if (link->open)
356                 netif_device_detach(dev);
357
358         return 0;
359 }
360
361 static int com20020_resume(struct pcmcia_device *link)
362 {
363         com20020_dev_t *info = link->priv;
364         struct net_device *dev = info->dev;
365
366         if (link->open) {
367                 int ioaddr = dev->base_addr;
368                 struct arcnet_local *lp = dev->priv;
369                 ARCRESET;
370         }
371
372         return 0;
373 }
374
375 static struct pcmcia_device_id com20020_ids[] = {
376         PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
377                         "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
378         PCMCIA_DEVICE_PROD_ID12("SoHard AG",
379                         "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
380         PCMCIA_DEVICE_NULL
381 };
382 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
383
384 static struct pcmcia_driver com20020_cs_driver = {
385         .owner          = THIS_MODULE,
386         .drv            = {
387                 .name   = "com20020_cs",
388         },
389         .probe          = com20020_probe,
390         .remove         = com20020_detach,
391         .id_table       = com20020_ids,
392         .suspend        = com20020_suspend,
393         .resume         = com20020_resume,
394 };
395
396 static int __init init_com20020_cs(void)
397 {
398         return pcmcia_register_driver(&com20020_cs_driver);
399 }
400
401 static void __exit exit_com20020_cs(void)
402 {
403         pcmcia_unregister_driver(&com20020_cs_driver);
404 }
405
406 module_init(init_com20020_cs);
407 module_exit(exit_com20020_cs);