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