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