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