Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[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 void com20020_config(dev_link_t *link);
122 static void com20020_release(dev_link_t *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_attach(struct pcmcia_device *p_dev)
142 {
143     dev_link_t *link;
144     com20020_dev_t *info;
145     struct net_device *dev;
146     struct arcnet_local *lp;
147
148     DEBUG(0, "com20020_attach()\n");
149
150     /* Create new network device */
151     link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
152     if (!link)
153         return -ENOMEM;
154
155     info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
156     if (!info)
157         goto fail_alloc_info;
158
159     dev = alloc_arcdev("");
160     if (!dev)
161         goto fail_alloc_dev;
162
163     memset(info, 0, sizeof(struct com20020_dev_t));
164     memset(link, 0, sizeof(struct dev_link_t));
165     lp = dev->priv;
166     lp->timeout = timeout;
167     lp->backplane = backplane;
168     lp->clockp = clockp;
169     lp->clockm = clockm & 3;
170     lp->hw.owner = THIS_MODULE;
171
172     /* fill in our module parameters as defaults */
173     dev->dev_addr[0] = node;
174
175     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
176     link->io.NumPorts1 = 16;
177     link->io.IOAddrLines = 16;
178     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
179     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
180     link->conf.Attributes = CONF_ENABLE_IRQ;
181     link->conf.Vcc = 50;
182     link->conf.IntType = INT_MEMORY_AND_IO;
183     link->conf.Present = PRESENT_OPTION;
184
185     link->irq.Instance = info->dev = dev;
186     link->priv = info;
187
188     link->state |= DEV_PRESENT;
189     com20020_config(link);
190
191     return 0;
192
193 fail_alloc_dev:
194     kfree(info);
195 fail_alloc_info:
196     kfree(link);
197     return -ENOMEM;
198 } /* com20020_attach */
199
200 /*======================================================================
201
202     This deletes a driver "instance".  The device is de-registered
203     with Card Services.  If it has been released, all local data
204     structures are freed.  Otherwise, the structures will be freed
205     when the device is released.
206
207 ======================================================================*/
208
209 static void com20020_detach(struct pcmcia_device *p_dev)
210 {
211     dev_link_t *link = dev_to_instance(p_dev);
212     struct com20020_dev_t *info = link->priv;
213     struct net_device *dev = info->dev;
214
215     DEBUG(1,"detach...\n");
216
217     DEBUG(0, "com20020_detach(0x%p)\n", link);
218
219     if (link->dev) {
220         DEBUG(1,"unregister...\n");
221
222         unregister_netdev(dev);
223
224         /*
225          * this is necessary because we register our IRQ separately
226          * from card services.
227          */
228         if (dev->irq)
229             free_irq(dev->irq, dev);
230     }
231
232     if (link->state & DEV_CONFIG)
233         com20020_release(link);
234
235     /* Unlink device structure, free bits */
236     DEBUG(1,"unlinking...\n");
237     if (link->priv)
238     {
239         dev = info->dev;
240         if (dev)
241         {
242             DEBUG(1,"kfree...\n");
243             free_netdev(dev);
244         }
245         DEBUG(1,"kfree2...\n");
246         kfree(info);
247     }
248     DEBUG(1,"kfree3...\n");
249     kfree(link);
250
251 } /* com20020_detach */
252
253 /*======================================================================
254
255     com20020_config() is scheduled to run after a CARD_INSERTION event
256     is received, to configure the PCMCIA socket, and to make the
257     device available to the system.
258
259 ======================================================================*/
260
261 #define CS_CHECK(fn, ret) \
262 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
263
264 static void com20020_config(dev_link_t *link)
265 {
266     struct arcnet_local *lp;
267     client_handle_t handle;
268     tuple_t tuple;
269     cisparse_t parse;
270     com20020_dev_t *info;
271     struct net_device *dev;
272     int i, last_ret, last_fn;
273     u_char buf[64];
274     int ioaddr;
275
276     handle = link->handle;
277     info = link->priv;
278     dev = info->dev;
279
280     DEBUG(1,"config...\n");
281
282     DEBUG(0, "com20020_config(0x%p)\n", link);
283
284     tuple.Attributes = 0;
285     tuple.TupleData = buf;
286     tuple.TupleDataMax = 64;
287     tuple.TupleOffset = 0;
288     tuple.DesiredTuple = CISTPL_CONFIG;
289     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
290     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
291     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
292     link->conf.ConfigBase = parse.config.base;
293
294     /* Configure card */
295     link->state |= DEV_CONFIG;
296
297     DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
298     i = !CS_SUCCESS;
299     if (!link->io.BasePort1)
300     {
301         for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
302         {
303             link->io.BasePort1 = ioaddr;
304             i = pcmcia_request_io(link->handle, &link->io);
305             if (i == CS_SUCCESS)
306                 break;
307         }
308     }
309     else
310         i = pcmcia_request_io(link->handle, &link->io);
311     
312     if (i != CS_SUCCESS)
313     {
314         DEBUG(1,"arcnet: requestIO failed totally!\n");
315         goto failed;
316     }
317         
318     ioaddr = dev->base_addr = link->io.BasePort1;
319     DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr);
320
321     DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
322            link->irq.AssignedIRQ,
323            link->irq.IRQInfo1, link->irq.IRQInfo2);
324     i = pcmcia_request_irq(link->handle, &link->irq);
325     if (i != CS_SUCCESS)
326     {
327         DEBUG(1,"arcnet: requestIRQ failed totally!\n");
328         goto failed;
329     }
330
331     dev->irq = link->irq.AssignedIRQ;
332
333     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
334
335     if (com20020_check(dev))
336     {
337         regdump(dev);
338         goto failed;
339     }
340     
341     lp = dev->priv;
342     lp->card_name = "PCMCIA COM20020";
343     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
344
345     link->dev = &info->node;
346     link->state &= ~DEV_CONFIG_PENDING;
347     SET_NETDEV_DEV(dev, &handle_to_dev(handle));
348
349     i = com20020_found(dev, 0); /* calls register_netdev */
350     
351     if (i != 0) {
352         DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
353         link->dev = NULL;
354         goto failed;
355     }
356
357     strcpy(info->node.dev_name, dev->name);
358
359     DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
360            dev->name, dev->base_addr, dev->irq);
361     return;
362
363 cs_failed:
364     cs_error(link->handle, last_fn, last_ret);
365 failed:
366     DEBUG(1,"com20020_config failed...\n");
367     com20020_release(link);
368 } /* com20020_config */
369
370 /*======================================================================
371
372     After a card is removed, com20020_release() will unregister the net
373     device, and release the PCMCIA configuration.  If the device is
374     still open, this will be postponed until it is closed.
375
376 ======================================================================*/
377
378 static void com20020_release(dev_link_t *link)
379 {
380
381     DEBUG(1,"release...\n");
382
383     DEBUG(0, "com20020_release(0x%p)\n", link);
384
385     pcmcia_release_configuration(link->handle);
386     pcmcia_release_io(link->handle, &link->io);
387     pcmcia_release_irq(link->handle, &link->irq);
388
389     link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
390 }
391
392 static int com20020_suspend(struct pcmcia_device *p_dev)
393 {
394         dev_link_t *link = dev_to_instance(p_dev);
395         com20020_dev_t *info = link->priv;
396         struct net_device *dev = info->dev;
397
398         link->state |= DEV_SUSPEND;
399         if (link->state & DEV_CONFIG) {
400                 if (link->open) {
401                         netif_device_detach(dev);
402                 }
403                 pcmcia_release_configuration(link->handle);
404         }
405
406         return 0;
407 }
408
409 static int com20020_resume(struct pcmcia_device *p_dev)
410 {
411         dev_link_t *link = dev_to_instance(p_dev);
412         com20020_dev_t *info = link->priv;
413         struct net_device *dev = info->dev;
414
415         link->state &= ~DEV_SUSPEND;
416         if (link->state & DEV_CONFIG) {
417                 pcmcia_request_configuration(link->handle, &link->conf);
418                 if (link->open) {
419                         int ioaddr = dev->base_addr;
420                         struct arcnet_local *lp = dev->priv;
421                         ARCRESET;
422                 }
423         }
424
425         return 0;
426 }
427
428 static struct pcmcia_device_id com20020_ids[] = {
429         PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
430         PCMCIA_DEVICE_NULL
431 };
432 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
433
434 static struct pcmcia_driver com20020_cs_driver = {
435         .owner          = THIS_MODULE,
436         .drv            = {
437                 .name   = "com20020_cs",
438         },
439         .probe          = com20020_attach,
440         .remove         = com20020_detach,
441         .id_table       = com20020_ids,
442         .suspend        = com20020_suspend,
443         .resume         = com20020_resume,
444 };
445
446 static int __init init_com20020_cs(void)
447 {
448         return pcmcia_register_driver(&com20020_cs_driver);
449 }
450
451 static void __exit exit_com20020_cs(void)
452 {
453         pcmcia_unregister_driver(&com20020_cs_driver);
454 }
455
456 module_init(init_com20020_cs);
457 module_exit(exit_com20020_cs);