[PATCH] pcmcia: unify detach, REMOVAL_EVENT handlers into one remove callback
[deliverable/linux.git] / drivers / net / pcmcia / com20020_cs.c
CommitLineData
1da177e4
LT
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
1da177e4
LT
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
58static int pc_debug = PCMCIA_DEBUG;
59module_param(pc_debug, int, 0);
60#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
61
62static 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)
96static inline void regdump(struct net_device *dev) { }
97
98#endif
99
100
101/*====================================================================*/
102
103/* Parameters that can be set with 'insmod' */
104
105static int node;
106static int timeout = 3;
107static int backplane;
108static int clockp;
109static int clockm;
110
111module_param(node, int, 0);
112module_param(timeout, int, 0);
113module_param(backplane, int, 0);
114module_param(clockp, int, 0);
115module_param(clockm, int, 0);
116
117MODULE_LICENSE("GPL");
118
119/*====================================================================*/
120
121static void com20020_config(dev_link_t *link);
122static void com20020_release(dev_link_t *link);
123static int com20020_event(event_t event, int priority,
124 event_callback_args_t *args);
125
126static dev_info_t dev_info = "com20020_cs";
127
128static dev_link_t *com20020_attach(void);
cc3b4866 129static void com20020_detach(struct pcmcia_device *p_dev);
1da177e4
LT
130
131static dev_link_t *dev_list;
132
133/*====================================================================*/
134
135typedef 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
148static 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;
1da177e4
LT
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);
cc3b4866 207 com20020_detach(link->handle);
1da177e4
LT
208 return NULL;
209 }
210
211 return link;
212
213fail_alloc_dev:
214 kfree(info);
215fail_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
cc3b4866 229static void com20020_detach(struct pcmcia_device *p_dev)
1da177e4 230{
cc3b4866 231 dev_link_t *link = dev_to_instance(p_dev);
1da177e4
LT
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
1da177e4
LT
264 /* Unlink device structure, free bits */
265 DEBUG(1,"unlinking...\n");
266 *linkp = link->next;
267 if (link->priv)
268 {
269 dev = info->dev;
270 if (dev)
271 {
272 DEBUG(1,"kfree...\n");
273 free_netdev(dev);
274 }
275 DEBUG(1,"kfree2...\n");
276 kfree(info);
277 }
278 DEBUG(1,"kfree3...\n");
279 kfree(link);
280
281} /* com20020_detach */
282
283/*======================================================================
284
285 com20020_config() is scheduled to run after a CARD_INSERTION event
286 is received, to configure the PCMCIA socket, and to make the
287 device available to the system.
288
289======================================================================*/
290
291#define CS_CHECK(fn, ret) \
292do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
293
294static void com20020_config(dev_link_t *link)
295{
296 struct arcnet_local *lp;
297 client_handle_t handle;
298 tuple_t tuple;
299 cisparse_t parse;
300 com20020_dev_t *info;
301 struct net_device *dev;
302 int i, last_ret, last_fn;
303 u_char buf[64];
304 int ioaddr;
305
306 handle = link->handle;
307 info = link->priv;
308 dev = info->dev;
309
310 DEBUG(1,"config...\n");
311
312 DEBUG(0, "com20020_config(0x%p)\n", link);
313
314 tuple.Attributes = 0;
315 tuple.TupleData = buf;
316 tuple.TupleDataMax = 64;
317 tuple.TupleOffset = 0;
318 tuple.DesiredTuple = CISTPL_CONFIG;
319 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
320 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
321 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
322 link->conf.ConfigBase = parse.config.base;
323
324 /* Configure card */
325 link->state |= DEV_CONFIG;
326
327 DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1);
328 i = !CS_SUCCESS;
329 if (!link->io.BasePort1)
330 {
331 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
332 {
333 link->io.BasePort1 = ioaddr;
334 i = pcmcia_request_io(link->handle, &link->io);
335 if (i == CS_SUCCESS)
336 break;
337 }
338 }
339 else
340 i = pcmcia_request_io(link->handle, &link->io);
341
342 if (i != CS_SUCCESS)
343 {
344 DEBUG(1,"arcnet: requestIO failed totally!\n");
345 goto failed;
346 }
347
348 ioaddr = dev->base_addr = link->io.BasePort1;
349 DEBUG(1,"arcnet: got ioaddr %Xh\n", ioaddr);
350
351 DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n",
352 link->irq.AssignedIRQ,
353 link->irq.IRQInfo1, link->irq.IRQInfo2);
354 i = pcmcia_request_irq(link->handle, &link->irq);
355 if (i != CS_SUCCESS)
356 {
357 DEBUG(1,"arcnet: requestIRQ failed totally!\n");
358 goto failed;
359 }
360
361 dev->irq = link->irq.AssignedIRQ;
362
363 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
364
365 if (com20020_check(dev))
366 {
367 regdump(dev);
368 goto failed;
369 }
370
371 lp = dev->priv;
372 lp->card_name = "PCMCIA COM20020";
373 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
374
375 link->dev = &info->node;
376 link->state &= ~DEV_CONFIG_PENDING;
377 SET_NETDEV_DEV(dev, &handle_to_dev(handle));
378
379 i = com20020_found(dev, 0); /* calls register_netdev */
380
381 if (i != 0) {
382 DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n");
383 link->dev = NULL;
384 goto failed;
385 }
386
387 strcpy(info->node.dev_name, dev->name);
388
389 DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n",
390 dev->name, dev->base_addr, dev->irq);
391 return;
392
393cs_failed:
394 cs_error(link->handle, last_fn, last_ret);
395failed:
396 DEBUG(1,"com20020_config failed...\n");
397 com20020_release(link);
398} /* com20020_config */
399
400/*======================================================================
401
402 After a card is removed, com20020_release() will unregister the net
403 device, and release the PCMCIA configuration. If the device is
404 still open, this will be postponed until it is closed.
405
406======================================================================*/
407
408static void com20020_release(dev_link_t *link)
409{
410
411 DEBUG(1,"release...\n");
412
413 DEBUG(0, "com20020_release(0x%p)\n", link);
414
415 pcmcia_release_configuration(link->handle);
416 pcmcia_release_io(link->handle, &link->io);
417 pcmcia_release_irq(link->handle, &link->irq);
418
419 link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
420}
421
98e4c28b
DB
422static int com20020_suspend(struct pcmcia_device *p_dev)
423{
424 dev_link_t *link = dev_to_instance(p_dev);
425 com20020_dev_t *info = link->priv;
426 struct net_device *dev = info->dev;
427
428 link->state |= DEV_SUSPEND;
429 if (link->state & DEV_CONFIG) {
430 if (link->open) {
431 netif_device_detach(dev);
432 }
433 pcmcia_release_configuration(link->handle);
434 }
435
436 return 0;
437}
438
439static int com20020_resume(struct pcmcia_device *p_dev)
440{
441 dev_link_t *link = dev_to_instance(p_dev);
442 com20020_dev_t *info = link->priv;
443 struct net_device *dev = info->dev;
444
445 link->state &= ~DEV_SUSPEND;
446 if (link->state & DEV_CONFIG) {
447 pcmcia_request_configuration(link->handle, &link->conf);
448 if (link->open) {
449 int ioaddr = dev->base_addr;
450 struct arcnet_local *lp = dev->priv;
451 ARCRESET;
452 }
453 }
454
455 return 0;
456}
457
1da177e4
LT
458/*======================================================================
459
460 The card status event handler. Mostly, this schedules other
461 stuff to run after an event is received. A CARD_REMOVAL event
462 also sets some flags to discourage the net drivers from trying
463 to talk to the card any more.
464
465======================================================================*/
466
467static int com20020_event(event_t event, int priority,
468 event_callback_args_t *args)
469{
470 dev_link_t *link = args->client_data;
1da177e4
LT
471
472 DEBUG(1, "com20020_event(0x%06x)\n", event);
473
474 switch (event) {
1da177e4
LT
475 case CS_EVENT_CARD_INSERTION:
476 link->state |= DEV_PRESENT;
477 com20020_config(link);
478 break;
1da177e4
LT
479 }
480 return 0;
481} /* com20020_event */
482
7fb22bb4
DB
483static struct pcmcia_device_id com20020_ids[] = {
484 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
485 PCMCIA_DEVICE_NULL
486};
487MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
1da177e4
LT
488
489static struct pcmcia_driver com20020_cs_driver = {
490 .owner = THIS_MODULE,
491 .drv = {
492 .name = "com20020_cs",
493 },
494 .attach = com20020_attach,
1e212f36 495 .event = com20020_event,
cc3b4866 496 .remove = com20020_detach,
7fb22bb4 497 .id_table = com20020_ids,
98e4c28b
DB
498 .suspend = com20020_suspend,
499 .resume = com20020_resume,
1da177e4
LT
500};
501
502static int __init init_com20020_cs(void)
503{
504 return pcmcia_register_driver(&com20020_cs_driver);
505}
506
507static void __exit exit_com20020_cs(void)
508{
509 pcmcia_unregister_driver(&com20020_cs_driver);
510 BUG_ON(dev_list != NULL);
511}
512
513module_init(init_com20020_cs);
514module_exit(exit_com20020_cs);
This page took 0.160767 seconds and 5 git commands to generate.