51e9cb0a6d1ed4f88a307927a26f64097c126465
[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 DEBUG
57
58 static void regdump(struct net_device *dev)
59 {
60     int ioaddr = dev->base_addr;
61     int count;
62     
63     printk("com20020 register dump:\n");
64     for (count = ioaddr; count < ioaddr + 16; count++)
65     {
66         if (!(count % 16))
67             printk("\n%04X: ", count);
68         printk("%02X ", inb(count));
69     }
70     printk("\n");
71     
72     printk("buffer0 dump:\n");
73         /* set up the address register */
74         count = 0;
75         outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
76         outb(count & 0xff, _ADDR_LO);
77     
78     for (count = 0; count < 256+32; count++)
79     {
80         if (!(count % 16))
81             printk("\n%04X: ", count);
82         
83         /* copy the data */
84         printk("%02X ", inb(_MEMDATA));
85     }
86     printk("\n");
87 }
88
89 #else
90
91 static inline void regdump(struct net_device *dev) { }
92
93 #endif
94
95
96 /*====================================================================*/
97
98 /* Parameters that can be set with 'insmod' */
99
100 static int node;
101 static int timeout = 3;
102 static int backplane;
103 static int clockp;
104 static int clockm;
105
106 module_param(node, int, 0);
107 module_param(timeout, int, 0);
108 module_param(backplane, int, 0);
109 module_param(clockp, int, 0);
110 module_param(clockm, int, 0);
111
112 MODULE_LICENSE("GPL");
113
114 /*====================================================================*/
115
116 static int com20020_config(struct pcmcia_device *link);
117 static void com20020_release(struct pcmcia_device *link);
118
119 static void com20020_detach(struct pcmcia_device *p_dev);
120
121 /*====================================================================*/
122
123 typedef struct com20020_dev_t {
124     struct net_device       *dev;
125     dev_node_t          node;
126 } com20020_dev_t;
127
128 /*======================================================================
129
130     com20020_attach() creates an "instance" of the driver, allocating
131     local data structures for one device.  The device is registered
132     with Card Services.
133
134 ======================================================================*/
135
136 static int com20020_probe(struct pcmcia_device *p_dev)
137 {
138     com20020_dev_t *info;
139     struct net_device *dev;
140     struct arcnet_local *lp;
141
142     dev_dbg(&p_dev->dev, "com20020_attach()\n");
143
144     /* Create new network device */
145     info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
146     if (!info)
147         goto fail_alloc_info;
148
149     dev = alloc_arcdev("");
150     if (!dev)
151         goto fail_alloc_dev;
152
153     lp = netdev_priv(dev);
154     lp->timeout = timeout;
155     lp->backplane = backplane;
156     lp->clockp = clockp;
157     lp->clockm = clockm & 3;
158     lp->hw.owner = THIS_MODULE;
159
160     /* fill in our module parameters as defaults */
161     dev->dev_addr[0] = node;
162
163     p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
164     p_dev->io.NumPorts1 = 16;
165     p_dev->io.IOAddrLines = 16;
166     p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
167     p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
168     p_dev->conf.Attributes = CONF_ENABLE_IRQ;
169     p_dev->conf.IntType = INT_MEMORY_AND_IO;
170
171     p_dev->irq.Instance = info->dev = dev;
172     p_dev->priv = info;
173
174     return com20020_config(p_dev);
175
176 fail_alloc_dev:
177     kfree(info);
178 fail_alloc_info:
179     return -ENOMEM;
180 } /* com20020_attach */
181
182 /*======================================================================
183
184     This deletes a driver "instance".  The device is de-registered
185     with Card Services.  If it has been released, all local data
186     structures are freed.  Otherwise, the structures will be freed
187     when the device is released.
188
189 ======================================================================*/
190
191 static void com20020_detach(struct pcmcia_device *link)
192 {
193     struct com20020_dev_t *info = link->priv;
194     struct net_device *dev = info->dev;
195
196     dev_dbg(&link->dev, "detach...\n");
197
198     dev_dbg(&link->dev, "com20020_detach\n");
199
200     if (link->dev_node) {
201         dev_dbg(&link->dev, "unregister...\n");
202
203         unregister_netdev(dev);
204
205         /*
206          * this is necessary because we register our IRQ separately
207          * from card services.
208          */
209         if (dev->irq)
210             free_irq(dev->irq, dev);
211     }
212
213     com20020_release(link);
214
215     /* Unlink device structure, free bits */
216     dev_dbg(&link->dev, "unlinking...\n");
217     if (link->priv)
218     {
219         dev = info->dev;
220         if (dev)
221         {
222             dev_dbg(&link->dev, "kfree...\n");
223             free_netdev(dev);
224         }
225         dev_dbg(&link->dev, "kfree2...\n");
226         kfree(info);
227     }
228
229 } /* com20020_detach */
230
231 /*======================================================================
232
233     com20020_config() is scheduled to run after a CARD_INSERTION event
234     is received, to configure the PCMCIA socket, and to make the
235     device available to the system.
236
237 ======================================================================*/
238
239 static int com20020_config(struct pcmcia_device *link)
240 {
241     struct arcnet_local *lp;
242     com20020_dev_t *info;
243     struct net_device *dev;
244     int i, ret;
245     int ioaddr;
246
247     info = link->priv;
248     dev = info->dev;
249
250     dev_dbg(&link->dev, "config...\n");
251
252     dev_dbg(&link->dev, "com20020_config\n");
253
254     dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1);
255     i = -ENODEV;
256     if (!link->io.BasePort1)
257     {
258         for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
259         {
260             link->io.BasePort1 = ioaddr;
261             i = pcmcia_request_io(link, &link->io);
262             if (i == 0)
263                 break;
264         }
265     }
266     else
267         i = pcmcia_request_io(link, &link->io);
268     
269     if (i != 0)
270     {
271         dev_dbg(&link->dev, "requestIO failed totally!\n");
272         goto failed;
273     }
274         
275     ioaddr = dev->base_addr = link->io.BasePort1;
276     dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
277
278     dev_dbg(&link->dev, "request IRQ %d (%Xh/%Xh)\n",
279            link->irq.AssignedIRQ,
280            link->irq.IRQInfo1, link->irq.IRQInfo2);
281     i = pcmcia_request_irq(link, &link->irq);
282     if (i != 0)
283     {
284         dev_dbg(&link->dev, "requestIRQ failed totally!\n");
285         goto failed;
286     }
287
288     dev->irq = link->irq.AssignedIRQ;
289
290     ret = pcmcia_request_configuration(link, &link->conf);
291     if (ret)
292             goto failed;
293
294     if (com20020_check(dev))
295     {
296         regdump(dev);
297         goto failed;
298     }
299     
300     lp = netdev_priv(dev);
301     lp->card_name = "PCMCIA COM20020";
302     lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
303
304     link->dev_node = &info->node;
305     SET_NETDEV_DEV(dev, &link->dev);
306
307     i = com20020_found(dev, 0); /* calls register_netdev */
308     
309     if (i != 0) {
310         dev_printk(KERN_NOTICE, &link->dev,
311                 "com20020_cs: com20020_found() failed\n");
312         link->dev_node = NULL;
313         goto failed;
314     }
315
316     strcpy(info->node.dev_name, dev->name);
317
318     dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
319            dev->name, dev->base_addr, dev->irq);
320     return 0;
321
322 failed:
323     dev_dbg(&link->dev, "com20020_config failed...\n");
324     com20020_release(link);
325     return -ENODEV;
326 } /* com20020_config */
327
328 /*======================================================================
329
330     After a card is removed, com20020_release() will unregister the net
331     device, and release the PCMCIA configuration.  If the device is
332     still open, this will be postponed until it is closed.
333
334 ======================================================================*/
335
336 static void com20020_release(struct pcmcia_device *link)
337 {
338         dev_dbg(&link->dev, "com20020_release\n");
339         pcmcia_disable_device(link);
340 }
341
342 static int com20020_suspend(struct pcmcia_device *link)
343 {
344         com20020_dev_t *info = link->priv;
345         struct net_device *dev = info->dev;
346
347         if (link->open)
348                 netif_device_detach(dev);
349
350         return 0;
351 }
352
353 static int com20020_resume(struct pcmcia_device *link)
354 {
355         com20020_dev_t *info = link->priv;
356         struct net_device *dev = info->dev;
357
358         if (link->open) {
359                 int ioaddr = dev->base_addr;
360                 struct arcnet_local *lp = netdev_priv(dev);
361                 ARCRESET;
362         }
363
364         return 0;
365 }
366
367 static struct pcmcia_device_id com20020_ids[] = {
368         PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
369                         "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
370         PCMCIA_DEVICE_PROD_ID12("SoHard AG",
371                         "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
372         PCMCIA_DEVICE_NULL
373 };
374 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
375
376 static struct pcmcia_driver com20020_cs_driver = {
377         .owner          = THIS_MODULE,
378         .drv            = {
379                 .name   = "com20020_cs",
380         },
381         .probe          = com20020_probe,
382         .remove         = com20020_detach,
383         .id_table       = com20020_ids,
384         .suspend        = com20020_suspend,
385         .resume         = com20020_resume,
386 };
387
388 static int __init init_com20020_cs(void)
389 {
390         return pcmcia_register_driver(&com20020_cs_driver);
391 }
392
393 static void __exit exit_com20020_cs(void)
394 {
395         pcmcia_unregister_driver(&com20020_cs_driver);
396 }
397
398 module_init(init_com20020_cs);
399 module_exit(exit_com20020_cs);