blob: f065c35cd4b75147f7f8184108f4ccc95df9cdb0 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56static void regdump(struct net_device *dev)
57{
Joe Perches636b8112010-08-12 12:22:51 +000058#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 int ioaddr = dev->base_addr;
60 int count;
61
Joe Perches636b8112010-08-12 12:22:51 +000062 netdev_dbg(dev, "register dump:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 for (count = ioaddr; count < ioaddr + 16; count++)
64 {
65 if (!(count % 16))
Joe Perches636b8112010-08-12 12:22:51 +000066 pr_cont("%04X:", count);
67 pr_cont(" %02X", inb(count));
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 }
Joe Perches636b8112010-08-12 12:22:51 +000069 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Joe Perches636b8112010-08-12 12:22:51 +000071 netdev_dbg(dev, "buffer0 dump:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 /* 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))
Joe Perches636b8112010-08-12 12:22:51 +000080 pr_cont("%04X:", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82 /* copy the data */
Joe Perches636b8112010-08-12 12:22:51 +000083 pr_cont(" %02X", inb(_MEMDATA));
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
Joe Perches636b8112010-08-12 12:22:51 +000085 pr_cont("\n");
86#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070087}
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90
91/*====================================================================*/
92
93/* Parameters that can be set with 'insmod' */
94
95static int node;
96static int timeout = 3;
97static int backplane;
98static int clockp;
99static int clockm;
100
101module_param(node, int, 0);
102module_param(timeout, int, 0);
103module_param(backplane, int, 0);
104module_param(clockp, int, 0);
105module_param(clockm, int, 0);
106
107MODULE_LICENSE("GPL");
108
109/*====================================================================*/
110
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200111static int com20020_config(struct pcmcia_device *link);
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200112static void com20020_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100114static void com20020_detach(struct pcmcia_device *p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/*====================================================================*/
117
118typedef struct com20020_dev_t {
119 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120} com20020_dev_t;
121
122/*======================================================================
123
124 com20020_attach() creates an "instance" of the driver, allocating
125 local data structures for one device. The device is registered
126 with Card Services.
127
128======================================================================*/
129
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200130static int com20020_probe(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 com20020_dev_t *info;
133 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 struct arcnet_local *lp;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100135
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200136 dev_dbg(&p_dev->dev, "com20020_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /* Create new network device */
Yoann Padioleaudd00cc42007-07-19 01:49:03 -0700139 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 if (!info)
141 goto fail_alloc_info;
142
143 dev = alloc_arcdev("");
144 if (!dev)
145 goto fail_alloc_dev;
146
Wang Chen4cf16532008-11-12 23:38:14 -0800147 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 lp->timeout = timeout;
149 lp->backplane = backplane;
150 lp->clockp = clockp;
151 lp->clockm = clockm & 3;
152 lp->hw.owner = THIS_MODULE;
153
154 /* fill in our module parameters as defaults */
155 dev->dev_addr[0] = node;
156
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200157 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
158 p_dev->resource[0]->end = 16;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100159 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
160 p_dev->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100162 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100163 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200165 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167fail_alloc_dev:
168 kfree(info);
169fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100170 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171} /* com20020_attach */
172
173/*======================================================================
174
175 This deletes a driver "instance". The device is de-registered
176 with Card Services. If it has been released, all local data
177 structures are freed. Otherwise, the structures will be freed
178 when the device is released.
179
180======================================================================*/
181
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200182static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
184 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100185 struct net_device *dev = info->dev;
186
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200187 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200189 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100191 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100193 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100194
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100195 /*
196 * this is necessary because we register our IRQ separately
197 * from card services.
198 */
199 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100202 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200205 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 if (link->priv)
207 {
208 dev = info->dev;
209 if (dev)
210 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200211 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 free_netdev(dev);
213 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200214 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 kfree(info);
216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217
218} /* com20020_detach */
219
220/*======================================================================
221
222 com20020_config() is scheduled to run after a CARD_INSERTION event
223 is received, to configure the PCMCIA socket, and to make the
224 device available to the system.
225
226======================================================================*/
227
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200228static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 com20020_dev_t *info;
232 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200233 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 int ioaddr;
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 info = link->priv;
237 dev = info->dev;
238
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200239 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200241 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200243 dev_dbg(&link->dev, "baseport1 is %Xh\n",
244 (unsigned int) link->resource[0]->start);
245
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200246 i = -ENODEV;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200247 link->io_lines = 16;
248
249 if (!link->resource[0]->start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 {
251 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
252 {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200253 link->resource[0]->start = ioaddr;
254 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200255 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 break;
257 }
258 }
259 else
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200260 i = pcmcia_request_io(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200262 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200264 dev_dbg(&link->dev, "requestIO failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 goto failed;
266 }
267
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200268 ioaddr = dev->base_addr = link->resource[0]->start;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200269 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100271 dev_dbg(&link->dev, "request IRQ %d\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100272 link->irq);
273 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200275 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 goto failed;
277 }
278
Dominik Brodowskieb141202010-03-07 12:21:16 +0100279 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200281 ret = pcmcia_request_configuration(link, &link->conf);
282 if (ret)
283 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 if (com20020_check(dev))
286 {
287 regdump(dev);
288 goto failed;
289 }
290
Wang Chen4cf16532008-11-12 23:38:14 -0800291 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 lp->card_name = "PCMCIA COM20020";
293 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
294
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100295 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 i = com20020_found(dev, 0); /* calls register_netdev */
298
299 if (i != 0) {
Joe Perches636b8112010-08-12 12:22:51 +0000300 dev_notice(&link->dev,
301 "com20020_found() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 goto failed;
303 }
304
Joe Perches636b8112010-08-12 12:22:51 +0000305 netdev_dbg(dev, "port %#3lx, irq %d\n",
306 dev->base_addr, dev->irq);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200307 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309failed:
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200310 dev_dbg(&link->dev, "com20020_config failed...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 com20020_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200312 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313} /* com20020_config */
314
315/*======================================================================
316
317 After a card is removed, com20020_release() will unregister the net
318 device, and release the PCMCIA configuration. If the device is
319 still open, this will be postponed until it is closed.
320
321======================================================================*/
322
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200323static void com20020_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200325 dev_dbg(&link->dev, "com20020_release\n");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200326 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200329static int com20020_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100330{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100331 com20020_dev_t *info = link->priv;
332 struct net_device *dev = info->dev;
333
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100334 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100335 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100336
337 return 0;
338}
339
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200340static int com20020_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100341{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100342 com20020_dev_t *info = link->priv;
343 struct net_device *dev = info->dev;
344
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100345 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100346 int ioaddr = dev->base_addr;
Wang Chen4cf16532008-11-12 23:38:14 -0800347 struct arcnet_local *lp = netdev_priv(dev);
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100348 ARCRESET;
349 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100350
351 return 0;
352}
353
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700354static struct pcmcia_device_id com20020_ids[] = {
Marc Sowen6bb1c392006-06-25 01:56:24 -0700355 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
356 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
357 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
358 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700359 PCMCIA_DEVICE_NULL
360};
361MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363static struct pcmcia_driver com20020_cs_driver = {
364 .owner = THIS_MODULE,
365 .drv = {
366 .name = "com20020_cs",
367 },
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);