blob: 3c400cfa82ae2e88c0e67c3f0582f75491be925e [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;
164 p_dev->conf.IntType = INT_MEMORY_AND_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100166 info->dev = dev;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100167 p_dev->priv = info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200169 return com20020_config(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
171fail_alloc_dev:
172 kfree(info);
173fail_alloc_info:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100174 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175} /* com20020_attach */
176
177/*======================================================================
178
179 This deletes a driver "instance". The device is de-registered
180 with Card Services. If it has been released, all local data
181 structures are freed. Otherwise, the structures will be freed
182 when the device is released.
183
184======================================================================*/
185
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200186static void com20020_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 struct com20020_dev_t *info = link->priv;
Dominik Brodowskib4635812005-11-14 21:25:35 +0100189 struct net_device *dev = info->dev;
190
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200191 dev_dbg(&link->dev, "detach...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200193 dev_dbg(&link->dev, "com20020_detach\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100195 dev_dbg(&link->dev, "unregister...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100197 unregister_netdev(dev);
Dominik Brodowskib4635812005-11-14 21:25:35 +0100198
Dominik Brodowskic7c2fa02010-03-20 19:39:26 +0100199 /*
200 * this is necessary because we register our IRQ separately
201 * from card services.
202 */
203 if (dev->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 free_irq(dev->irq, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100206 com20020_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 /* Unlink device structure, free bits */
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200209 dev_dbg(&link->dev, "unlinking...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 if (link->priv)
211 {
212 dev = info->dev;
213 if (dev)
214 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200215 dev_dbg(&link->dev, "kfree...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 free_netdev(dev);
217 }
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200218 dev_dbg(&link->dev, "kfree2...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 kfree(info);
220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222} /* com20020_detach */
223
224/*======================================================================
225
226 com20020_config() is scheduled to run after a CARD_INSERTION event
227 is received, to configure the PCMCIA socket, and to make the
228 device available to the system.
229
230======================================================================*/
231
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200232static int com20020_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 struct arcnet_local *lp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 com20020_dev_t *info;
236 struct net_device *dev;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200237 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 int ioaddr;
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 info = link->priv;
241 dev = info->dev;
242
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200243 dev_dbg(&link->dev, "config...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200245 dev_dbg(&link->dev, "com20020_config\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200247 dev_dbg(&link->dev, "baseport1 is %Xh\n",
248 (unsigned int) link->resource[0]->start);
249
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200250 i = -ENODEV;
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200251 link->io_lines = 16;
252
253 if (!link->resource[0]->start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 {
255 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
256 {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200257 link->resource[0]->start = ioaddr;
258 i = pcmcia_request_io(link);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200259 if (i == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 break;
261 }
262 }
263 else
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200264 i = pcmcia_request_io(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200266 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200268 dev_dbg(&link->dev, "requestIO failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 goto failed;
270 }
271
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200272 ioaddr = dev->base_addr = link->resource[0]->start;
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200273 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Dominik Brodowski5fa91672009-11-08 17:24:46 +0100275 dev_dbg(&link->dev, "request IRQ %d\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100276 link->irq);
277 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200279 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 goto failed;
281 }
282
Dominik Brodowskieb141202010-03-07 12:21:16 +0100283 dev->irq = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200285 ret = pcmcia_request_configuration(link, &link->conf);
286 if (ret)
287 goto failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 if (com20020_check(dev))
290 {
291 regdump(dev);
292 goto failed;
293 }
294
Wang Chen4cf16532008-11-12 23:38:14 -0800295 lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 lp->card_name = "PCMCIA COM20020";
297 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
298
Dominik Brodowskidd2e5a12009-11-03 10:27:34 +0100299 SET_NETDEV_DEV(dev, &link->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 i = com20020_found(dev, 0); /* calls register_netdev */
302
303 if (i != 0) {
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200304 dev_printk(KERN_NOTICE, &link->dev,
305 "com20020_cs: com20020_found() failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 goto failed;
307 }
308
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200309 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 dev->name, dev->base_addr, dev->irq);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200311 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313failed:
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200314 dev_dbg(&link->dev, "com20020_config failed...\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 com20020_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200316 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317} /* com20020_config */
318
319/*======================================================================
320
321 After a card is removed, com20020_release() will unregister the net
322 device, and release the PCMCIA configuration. If the device is
323 still open, this will be postponed until it is closed.
324
325======================================================================*/
326
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200327static void com20020_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
Dominik Brodowskidd0fab52009-10-24 15:51:05 +0200329 dev_dbg(&link->dev, "com20020_release\n");
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200330 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331}
332
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200333static int com20020_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100334{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100335 com20020_dev_t *info = link->priv;
336 struct net_device *dev = info->dev;
337
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100338 if (link->open)
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100339 netif_device_detach(dev);
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100340
341 return 0;
342}
343
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200344static int com20020_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100345{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100346 com20020_dev_t *info = link->priv;
347 struct net_device *dev = info->dev;
348
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100349 if (link->open) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100350 int ioaddr = dev->base_addr;
Wang Chen4cf16532008-11-12 23:38:14 -0800351 struct arcnet_local *lp = netdev_priv(dev);
Dominik Brodowski8661bb52006-03-02 00:02:33 +0100352 ARCRESET;
353 }
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100354
355 return 0;
356}
357
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700358static struct pcmcia_device_id com20020_ids[] = {
Marc Sowen6bb1c392006-06-25 01:56:24 -0700359 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
360 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
361 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
362 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700363 PCMCIA_DEVICE_NULL
364};
365MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367static struct pcmcia_driver com20020_cs_driver = {
368 .owner = THIS_MODULE,
369 .drv = {
370 .name = "com20020_cs",
371 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200372 .probe = com20020_probe,
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100373 .remove = com20020_detach,
Dominik Brodowski7fb22bb2005-06-27 16:28:38 -0700374 .id_table = com20020_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100375 .suspend = com20020_suspend,
376 .resume = com20020_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377};
378
379static int __init init_com20020_cs(void)
380{
381 return pcmcia_register_driver(&com20020_cs_driver);
382}
383
384static void __exit exit_com20020_cs(void)
385{
386 pcmcia_unregister_driver(&com20020_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
389module_init(init_com20020_cs);
390module_exit(exit_com20020_cs);