blob: a58eafed42a5211c9cff30a39ff3f0be9dd399f4 [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 Brodowski90abdc32010-07-24 17:23:51 +0200161 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
162 p_dev->resource[0]->end = 16;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100163 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100165 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100166 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200168 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
170fail_alloc_dev:
171 kfree(info);
172fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100173 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174} /* com20020_attach */
175
176/*======================================================================
177
178 This deletes a driver "instance". The device is de-registered
179 with Card Services. If it has been released, all local data
180 structures are freed. Otherwise, the structures will be freed
181 when the device is released.
182
183======================================================================*/
184
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200185static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
187 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100188 struct net_device *dev = info->dev;
189
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200190 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200192 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100194 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100196 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100197
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100198 /*
199 * this is necessary because we register our IRQ separately
200 * from card services.
201 */
202 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100205 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200208 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 if (link->priv)
210 {
211 dev = info->dev;
212 if (dev)
213 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200214 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 free_netdev(dev);
216 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200217 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 kfree(info);
219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221} /* com20020_detach */
222
223/*======================================================================
224
225 com20020_config() is scheduled to run after a CARD_INSERTION event
226 is received, to configure the PCMCIA socket, and to make the
227 device available to the system.
228
229======================================================================*/
230
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200231static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 com20020_dev_t *info;
235 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200236 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 int ioaddr;
238
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 info = link->priv;
240 dev = info->dev;
241
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200242 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200244 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200246 dev_dbg(&link->dev, "baseport1 is %Xh\n",
247 (unsigned int) link->resource[0]->start);
248
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200249 i = -ENODEV;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200250 link->io_lines = 16;
251
252 if (!link->resource[0]->start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 {
254 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
255 {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200256 link->resource[0]->start = ioaddr;
257 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200258 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 break;
260 }
261 }
262 else
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200263 i = pcmcia_request_io(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200265 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200267 dev_dbg(&link->dev, "requestIO failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 goto failed;
269 }
270
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200271 ioaddr = dev->base_addr = link->resource[0]->start;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200272 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100274 dev_dbg(&link->dev, "request IRQ %d\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100275 link->irq);
276 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200278 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 goto failed;
280 }
281
Dominik Brodowskieb141202010-03-07 12:21:16 +0100282 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200284 ret = pcmcia_request_configuration(link, &link->conf);
285 if (ret)
286 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
288 if (com20020_check(dev))
289 {
290 regdump(dev);
291 goto failed;
292 }
293
Wang Chen4cf16532008-11-12 23:38:14 -0800294 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 lp->card_name = "PCMCIA COM20020";
296 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
297
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100298 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 i = com20020_found(dev, 0); /* calls register_netdev */
301
302 if (i != 0) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200303 dev_printk(KERN_NOTICE, &link->dev,
304 "com20020_cs: com20020_found() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 goto failed;
306 }
307
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200308 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 dev->name, dev->base_addr, dev->irq);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200310 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312failed:
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200313 dev_dbg(&link->dev, "com20020_config failed...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 com20020_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200315 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316} /* com20020_config */
317
318/*======================================================================
319
320 After a card is removed, com20020_release() will unregister the net
321 device, and release the PCMCIA configuration. If the device is
322 still open, this will be postponed until it is closed.
323
324======================================================================*/
325
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200326static void com20020_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200328 dev_dbg(&link->dev, "com20020_release\n");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200329 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330}
331
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200332static int com20020_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100333{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100334 com20020_dev_t *info = link->priv;
335 struct net_device *dev = info->dev;
336
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100337 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100338 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100339
340 return 0;
341}
342
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200343static int com20020_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100344{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100345 com20020_dev_t *info = link->priv;
346 struct net_device *dev = info->dev;
347
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100348 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100349 int ioaddr = dev->base_addr;
Wang Chen4cf16532008-11-12 23:38:14 -0800350 struct arcnet_local *lp = netdev_priv(dev);
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100351 ARCRESET;
352 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100353
354 return 0;
355}
356
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700357static struct pcmcia_device_id com20020_ids[] = {
Marc Sowen6bb1c392006-06-25 01:56:24 -0700358 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
359 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
360 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
361 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700362 PCMCIA_DEVICE_NULL
363};
364MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366static struct pcmcia_driver com20020_cs_driver = {
367 .owner = THIS_MODULE,
368 .drv = {
369 .name = "com20020_cs",
370 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200371 .probe = com20020_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100372 .remove = com20020_detach,
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700373 .id_table = com20020_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100374 .suspend = com20020_suspend,
375 .resume = com20020_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376};
377
378static int __init init_com20020_cs(void)
379{
380 return pcmcia_register_driver(&com20020_cs_driver);
381}
382
383static void __exit exit_com20020_cs(void)
384{
385 pcmcia_unregister_driver(&com20020_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
388module_init(init_com20020_cs);
389module_exit(exit_com20020_cs);