blob: 3b53818e3eef02d7e53aac7411eaafaf6bc8559f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <pcmcia/cs.h>
47#include <pcmcia/cistpl.h>
48#include <pcmcia/ds.h>
49
50#include <asm/io.h>
51#include <asm/system.h>
52
53#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
54
Dominik Brodowskidd0fab52009-10-24 15:51:05 +020055#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static void regdump(struct net_device *dev)
58{
59 int ioaddr = dev->base_addr;
60 int count;
61
62 printk("com20020 register dump:\n");
63 for (count = ioaddr; count < ioaddr + 16; count++)
64 {
65 if (!(count % 16))
66 printk("\n%04X: ", count);
67 printk("%02X ", inb(count));
68 }
69 printk("\n");
70
71 printk("buffer0 dump:\n");
72 /* set up the address register */
73 count = 0;
74 outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
75 outb(count & 0xff, _ADDR_LO);
76
77 for (count = 0; count < 256+32; count++)
78 {
79 if (!(count % 16))
80 printk("\n%04X: ", count);
81
82 /* copy the data */
83 printk("%02X ", inb(_MEMDATA));
84 }
85 printk("\n");
86}
87
88#else
89
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static inline void regdump(struct net_device *dev) { }
91
92#endif
93
94
95/*====================================================================*/
96
97/* Parameters that can be set with 'insmod' */
98
99static int node;
100static int timeout = 3;
101static int backplane;
102static int clockp;
103static int clockm;
104
105module_param(node, int, 0);
106module_param(timeout, int, 0);
107module_param(backplane, int, 0);
108module_param(clockp, int, 0);
109module_param(clockm, int, 0);
110
111MODULE_LICENSE("GPL");
112
113/*====================================================================*/
114
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200115static int com20020_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200116static void com20020_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100118static void com20020_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/*====================================================================*/
121
122typedef struct com20020_dev_t {
123 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124} com20020_dev_t;
125
126/*======================================================================
127
128 com20020_attach() creates an "instance" of the driver, allocating
129 local data structures for one device. The device is registered
130 with Card Services.
131
132======================================================================*/
133
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200134static int com20020_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 com20020_dev_t *info;
137 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 struct arcnet_local *lp;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100139
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200140 dev_dbg(&p_dev->dev, "com20020_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 /* Create new network device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700143 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 if (!info)
145 goto fail_alloc_info;
146
147 dev = alloc_arcdev("");
148 if (!dev)
149 goto fail_alloc_dev;
150
Wang Chen4cf16532008-11-12 23:38:14 -0800151 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 lp->timeout = timeout;
153 lp->backplane = backplane;
154 lp->clockp = clockp;
155 lp->clockm = clockm & 3;
156 lp->hw.owner = THIS_MODULE;
157
158 /* fill in our module parameters as defaults */
159 dev->dev_addr[0] = node;
160
Dominik Brodowskifd238232006-03-05 10:45:09 +0100161 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
162 p_dev->io.NumPorts1 = 16;
163 p_dev->io.IOAddrLines = 16;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100164 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
165 p_dev->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100167 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100168 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200170 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172fail_alloc_dev:
173 kfree(info);
174fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100175 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176} /* com20020_attach */
177
178/*======================================================================
179
180 This deletes a driver "instance". The device is de-registered
181 with Card Services. If it has been released, all local data
182 structures are freed. Otherwise, the structures will be freed
183 when the device is released.
184
185======================================================================*/
186
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200187static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
189 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100190 struct net_device *dev = info->dev;
191
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200192 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200194 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100196 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100198 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100199
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100200 /*
201 * this is necessary because we register our IRQ separately
202 * from card services.
203 */
204 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100207 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200210 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 if (link->priv)
212 {
213 dev = info->dev;
214 if (dev)
215 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200216 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 free_netdev(dev);
218 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200219 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 kfree(info);
221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223} /* com20020_detach */
224
225/*======================================================================
226
227 com20020_config() is scheduled to run after a CARD_INSERTION event
228 is received, to configure the PCMCIA socket, and to make the
229 device available to the system.
230
231======================================================================*/
232
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200233static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
235 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 com20020_dev_t *info;
237 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200238 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 int ioaddr;
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 info = link->priv;
242 dev = info->dev;
243
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200244 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200246 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200248 dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200249 i = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if (!link->io.BasePort1)
251 {
252 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
253 {
254 link->io.BasePort1 = ioaddr;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200255 i = pcmcia_request_io(link, &link->io);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200256 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 break;
258 }
259 }
260 else
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200261 i = pcmcia_request_io(link, &link->io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200263 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200265 dev_dbg(&link->dev, "requestIO failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 goto failed;
267 }
268
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200269 ioaddr = dev->base_addr = link->resource[0]->start;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200270 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100272 dev_dbg(&link->dev, "request IRQ %d\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100273 link->irq);
274 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200276 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 goto failed;
278 }
279
Dominik Brodowskieb141202010-03-07 12:21:16 +0100280 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200282 ret = pcmcia_request_configuration(link, &link->conf);
283 if (ret)
284 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286 if (com20020_check(dev))
287 {
288 regdump(dev);
289 goto failed;
290 }
291
Wang Chen4cf16532008-11-12 23:38:14 -0800292 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 lp->card_name = "PCMCIA COM20020";
294 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
295
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100296 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 i = com20020_found(dev, 0); /* calls register_netdev */
299
300 if (i != 0) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200301 dev_printk(KERN_NOTICE, &link->dev,
302 "com20020_cs: com20020_found() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 goto failed;
304 }
305
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200306 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 dev->name, dev->base_addr, dev->irq);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200308 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310failed:
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200311 dev_dbg(&link->dev, "com20020_config failed...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 com20020_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200313 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314} /* com20020_config */
315
316/*======================================================================
317
318 After a card is removed, com20020_release() will unregister the net
319 device, and release the PCMCIA configuration. If the device is
320 still open, this will be postponed until it is closed.
321
322======================================================================*/
323
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200324static void com20020_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200326 dev_dbg(&link->dev, "com20020_release\n");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200327 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200330static int com20020_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100331{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100332 com20020_dev_t *info = link->priv;
333 struct net_device *dev = info->dev;
334
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100335 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100336 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100337
338 return 0;
339}
340
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200341static int com20020_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100342{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100343 com20020_dev_t *info = link->priv;
344 struct net_device *dev = info->dev;
345
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100346 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100347 int ioaddr = dev->base_addr;
Wang Chen4cf16532008-11-12 23:38:14 -0800348 struct arcnet_local *lp = netdev_priv(dev);
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100349 ARCRESET;
350 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100351
352 return 0;
353}
354
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700355static struct pcmcia_device_id com20020_ids[] = {
Marc Sowen6bb1c392006-06-25 01:56:24 -0700356 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
357 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
358 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
359 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700360 PCMCIA_DEVICE_NULL
361};
362MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364static struct pcmcia_driver com20020_cs_driver = {
365 .owner = THIS_MODULE,
366 .drv = {
367 .name = "com20020_cs",
368 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200369 .probe = com20020_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100370 .remove = com20020_detach,
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700371 .id_table = com20020_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100372 .suspend = com20020_suspend,
373 .resume = com20020_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374};
375
376static int __init init_com20020_cs(void)
377{
378 return pcmcia_register_driver(&com20020_cs_driver);
379}
380
381static void __exit exit_com20020_cs(void)
382{
383 pcmcia_unregister_driver(&com20020_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384}
385
386module_init(init_com20020_cs);
387module_exit(exit_com20020_cs);