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