blob: 5643f94541bc9ed07a14e67620655ca05a30f8bd [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_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
Dominik Brodowskidd0fab52009-10-24 15:51:05 +020056#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
58static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -070091static inline void regdump(struct net_device *dev) { }
92
93#endif
94
95
96/*====================================================================*/
97
98/* Parameters that can be set with 'insmod' */
99
100static int node;
101static int timeout = 3;
102static int backplane;
103static int clockp;
104static int clockm;
105
106module_param(node, int, 0);
107module_param(timeout, int, 0);
108module_param(backplane, int, 0);
109module_param(clockp, int, 0);
110module_param(clockm, int, 0);
111
112MODULE_LICENSE("GPL");
113
114/*====================================================================*/
115
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200116static int com20020_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200117static void com20020_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100119static void com20020_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/*====================================================================*/
122
123typedef struct com20020_dev_t {
124 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125} com20020_dev_t;
126
127/*======================================================================
128
129 com20020_attach() creates an "instance" of the driver, allocating
130 local data structures for one device. The device is registered
131 with Card Services.
132
133======================================================================*/
134
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200135static int com20020_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 com20020_dev_t *info;
138 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 struct arcnet_local *lp;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100140
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200141 dev_dbg(&p_dev->dev, "com20020_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 /* Create new network device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700144 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 if (!info)
146 goto fail_alloc_info;
147
148 dev = alloc_arcdev("");
149 if (!dev)
150 goto fail_alloc_dev;
151
Wang Chen4cf16532008-11-12 23:38:14 -0800152 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 lp->timeout = timeout;
154 lp->backplane = backplane;
155 lp->clockp = clockp;
156 lp->clockm = clockm & 3;
157 lp->hw.owner = THIS_MODULE;
158
159 /* fill in our module parameters as defaults */
160 dev->dev_addr[0] = node;
161
Dominik Brodowskifd238232006-03-05 10:45:09 +0100162 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
163 p_dev->io.NumPorts1 = 16;
164 p_dev->io.IOAddrLines = 16;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100165 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
166 p_dev->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100168 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100169 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200171 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173fail_alloc_dev:
174 kfree(info);
175fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100176 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177} /* com20020_attach */
178
179/*======================================================================
180
181 This deletes a driver "instance". The device is de-registered
182 with Card Services. If it has been released, all local data
183 structures are freed. Otherwise, the structures will be freed
184 when the device is released.
185
186======================================================================*/
187
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200188static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
190 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100191 struct net_device *dev = info->dev;
192
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200193 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200195 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100197 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100199 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100200
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100201 /*
202 * this is necessary because we register our IRQ separately
203 * from card services.
204 */
205 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100208 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200211 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (link->priv)
213 {
214 dev = info->dev;
215 if (dev)
216 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200217 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 free_netdev(dev);
219 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200220 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 kfree(info);
222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
224} /* com20020_detach */
225
226/*======================================================================
227
228 com20020_config() is scheduled to run after a CARD_INSERTION event
229 is received, to configure the PCMCIA socket, and to make the
230 device available to the system.
231
232======================================================================*/
233
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200234static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235{
236 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 com20020_dev_t *info;
238 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200239 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 int ioaddr;
241
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 info = link->priv;
243 dev = info->dev;
244
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200245 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200247 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200249 dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200250 i = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 if (!link->io.BasePort1)
252 {
253 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
254 {
255 link->io.BasePort1 = ioaddr;
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200256 i = pcmcia_request_io(link, &link->io);
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 Brodowskifba395e2006-03-31 17:21:06 +0200262 i = pcmcia_request_io(link, &link->io);
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
270 ioaddr = dev->base_addr = link->io.BasePort1;
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 Brodowskidd0fab52009-10-24 15:51:05 +0200283 ret = pcmcia_request_configuration(link, &link->conf);
284 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,
367 .drv = {
368 .name = "com20020_cs",
369 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200370 .probe = com20020_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100371 .remove = com20020_detach,
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700372 .id_table = com20020_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100373 .suspend = com20020_suspend,
374 .resume = com20020_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375};
376
377static int __init init_com20020_cs(void)
378{
379 return pcmcia_register_driver(&com20020_cs_driver);
380}
381
382static void __exit exit_com20020_cs(void)
383{
384 pcmcia_unregister_driver(&com20020_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
387module_init(init_com20020_cs);
388module_exit(exit_com20020_cs);