blob: a5d918ea5b1340d42f318944d1e12fa0dfcb3be3 [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/cistpl.h>
47#include <pcmcia/ds.h>
48
49#include <asm/io.h>
50#include <asm/system.h>
51
52#define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
53
Dominik Brodowskidd0fab52009-10-24 15:51:05 +020054#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56static void regdump(struct net_device *dev)
57{
58 int ioaddr = dev->base_addr;
59 int count;
60
61 printk("com20020 register dump:\n");
62 for (count = ioaddr; count < ioaddr + 16; count++)
63 {
64 if (!(count % 16))
65 printk("\n%04X: ", count);
66 printk("%02X ", inb(count));
67 }
68 printk("\n");
69
70 printk("buffer0 dump:\n");
71 /* set up the address register */
72 count = 0;
73 outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
74 outb(count & 0xff, _ADDR_LO);
75
76 for (count = 0; count < 256+32; count++)
77 {
78 if (!(count % 16))
79 printk("\n%04X: ", count);
80
81 /* copy the data */
82 printk("%02X ", inb(_MEMDATA));
83 }
84 printk("\n");
85}
86
87#else
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static inline void regdump(struct net_device *dev) { }
90
91#endif
92
93
94/*====================================================================*/
95
96/* Parameters that can be set with 'insmod' */
97
98static int node;
99static int timeout = 3;
100static int backplane;
101static int clockp;
102static int clockm;
103
104module_param(node, int, 0);
105module_param(timeout, int, 0);
106module_param(backplane, int, 0);
107module_param(clockp, int, 0);
108module_param(clockm, int, 0);
109
110MODULE_LICENSE("GPL");
111
112/*====================================================================*/
113
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200114static int com20020_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200115static void com20020_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100117static void com20020_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*====================================================================*/
120
121typedef struct com20020_dev_t {
122 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123} com20020_dev_t;
124
125/*======================================================================
126
127 com20020_attach() creates an "instance" of the driver, allocating
128 local data structures for one device. The device is registered
129 with Card Services.
130
131======================================================================*/
132
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200133static int com20020_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 com20020_dev_t *info;
136 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct arcnet_local *lp;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100138
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200139 dev_dbg(&p_dev->dev, "com20020_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 /* Create new network device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700142 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if (!info)
144 goto fail_alloc_info;
145
146 dev = alloc_arcdev("");
147 if (!dev)
148 goto fail_alloc_dev;
149
Wang Chen4cf16532008-11-12 23:38:14 -0800150 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 lp->timeout = timeout;
152 lp->backplane = backplane;
153 lp->clockp = clockp;
154 lp->clockm = clockm & 3;
155 lp->hw.owner = THIS_MODULE;
156
157 /* fill in our module parameters as defaults */
158 dev->dev_addr[0] = node;
159
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200160 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
161 p_dev->resource[0]->end = 16;
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200162 p_dev->config_flags |= CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100164 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100165 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200167 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169fail_alloc_dev:
170 kfree(info);
171fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100172 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173} /* com20020_attach */
174
175/*======================================================================
176
177 This deletes a driver "instance". The device is de-registered
178 with Card Services. If it has been released, all local data
179 structures are freed. Otherwise, the structures will be freed
180 when the device is released.
181
182======================================================================*/
183
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200184static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100187 struct net_device *dev = info->dev;
188
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200189 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200191 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100193 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100195 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100196
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100197 /*
198 * this is necessary because we register our IRQ separately
199 * from card services.
200 */
201 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100204 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200207 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (link->priv)
209 {
210 dev = info->dev;
211 if (dev)
212 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200213 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 free_netdev(dev);
215 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200216 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 kfree(info);
218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
220} /* com20020_detach */
221
222/*======================================================================
223
224 com20020_config() is scheduled to run after a CARD_INSERTION event
225 is received, to configure the PCMCIA socket, and to make the
226 device available to the system.
227
228======================================================================*/
229
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200230static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 com20020_dev_t *info;
234 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200235 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 int ioaddr;
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 info = link->priv;
239 dev = info->dev;
240
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200241 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200243 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200245 dev_dbg(&link->dev, "baseport1 is %Xh\n",
246 (unsigned int) link->resource[0]->start);
247
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200248 i = -ENODEV;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200249 link->io_lines = 16;
250
251 if (!link->resource[0]->start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 {
253 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
254 {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200255 link->resource[0]->start = ioaddr;
256 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200257 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 break;
259 }
260 }
261 else
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200262 i = pcmcia_request_io(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200264 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200266 dev_dbg(&link->dev, "requestIO failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 goto failed;
268 }
269
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200270 ioaddr = dev->base_addr = link->resource[0]->start;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200271 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100273 dev_dbg(&link->dev, "request IRQ %d\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100274 link->irq);
275 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200277 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 goto failed;
279 }
280
Dominik Brodowskieb141202010-03-07 12:21:16 +0100281 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200283 ret = pcmcia_enable_device(link);
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200284 if (ret)
285 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 if (com20020_check(dev))
288 {
289 regdump(dev);
290 goto failed;
291 }
292
Wang Chen4cf16532008-11-12 23:38:14 -0800293 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 lp->card_name = "PCMCIA COM20020";
295 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
296
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100297 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 i = com20020_found(dev, 0); /* calls register_netdev */
300
301 if (i != 0) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200302 dev_printk(KERN_NOTICE, &link->dev,
303 "com20020_cs: com20020_found() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 goto failed;
305 }
306
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200307 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 dev->name, dev->base_addr, dev->irq);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200309 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311failed:
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200312 dev_dbg(&link->dev, "com20020_config failed...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 com20020_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200314 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315} /* com20020_config */
316
317/*======================================================================
318
319 After a card is removed, com20020_release() will unregister the net
320 device, and release the PCMCIA configuration. If the device is
321 still open, this will be postponed until it is closed.
322
323======================================================================*/
324
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200325static void com20020_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200327 dev_dbg(&link->dev, "com20020_release\n");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200328 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200331static int com20020_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100332{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100333 com20020_dev_t *info = link->priv;
334 struct net_device *dev = info->dev;
335
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100336 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100337 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100338
339 return 0;
340}
341
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200342static int com20020_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100343{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100344 com20020_dev_t *info = link->priv;
345 struct net_device *dev = info->dev;
346
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100347 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100348 int ioaddr = dev->base_addr;
Wang Chen4cf16532008-11-12 23:38:14 -0800349 struct arcnet_local *lp = netdev_priv(dev);
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100350 ARCRESET;
351 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100352
353 return 0;
354}
355
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700356static struct pcmcia_device_id com20020_ids[] = {
Marc Sowen6bb1c392006-06-25 01:56:24 -0700357 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
358 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
359 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
360 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700361 PCMCIA_DEVICE_NULL
362};
363MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365static struct pcmcia_driver com20020_cs_driver = {
366 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200367 .name = "com20020_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200368 .probe = com20020_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100369 .remove = com20020_detach,
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700370 .id_table = com20020_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100371 .suspend = com20020_suspend,
372 .resume = com20020_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373};
374
375static int __init init_com20020_cs(void)
376{
377 return pcmcia_register_driver(&com20020_cs_driver);
378}
379
380static void __exit exit_com20020_cs(void)
381{
382 pcmcia_unregister_driver(&com20020_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
385module_init(init_com20020_cs);
386module_exit(exit_com20020_cs);