1330278cdSJeff Kirsher /*
2330278cdSJeff Kirsher * Linux ARCnet driver - COM20020 PCMCIA support
3330278cdSJeff Kirsher *
4330278cdSJeff Kirsher * Written 1994-1999 by Avery Pennarun,
5330278cdSJeff Kirsher * based on an ISA version by David Woodhouse.
6330278cdSJeff Kirsher * Derived from ibmtr_cs.c by Steve Kipisz (pcmcia-cs 3.1.4)
7330278cdSJeff Kirsher * which was derived from pcnet_cs.c by David Hinds.
8330278cdSJeff Kirsher * Some additional portions derived from skeleton.c by Donald Becker.
9330278cdSJeff Kirsher *
10330278cdSJeff Kirsher * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
11330278cdSJeff Kirsher * for sponsoring the further development of this driver.
12330278cdSJeff Kirsher *
13330278cdSJeff Kirsher * **********************
14330278cdSJeff Kirsher *
15330278cdSJeff Kirsher * The original copyright of skeleton.c was as follows:
16330278cdSJeff Kirsher *
17330278cdSJeff Kirsher * skeleton.c Written 1993 by Donald Becker.
18330278cdSJeff Kirsher * Copyright 1993 United States Government as represented by the
19330278cdSJeff Kirsher * Director, National Security Agency. This software may only be used
20330278cdSJeff Kirsher * and distributed according to the terms of the GNU General Public License as
21330278cdSJeff Kirsher * modified by SRC, incorporated herein by reference.
22330278cdSJeff Kirsher *
23330278cdSJeff Kirsher * **********************
24330278cdSJeff Kirsher * Changes:
25330278cdSJeff Kirsher * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
26330278cdSJeff Kirsher * - reorganize kmallocs in com20020_attach, checking all for failure
27330278cdSJeff Kirsher * and releasing the previous allocations if one fails
28330278cdSJeff Kirsher * **********************
29330278cdSJeff Kirsher *
30330278cdSJeff Kirsher * For more details, see drivers/net/arcnet.c
31330278cdSJeff Kirsher *
32330278cdSJeff Kirsher * **********************
33330278cdSJeff Kirsher */
3405a24b23SJoe Perches
3505a24b23SJoe Perches #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
3605a24b23SJoe Perches
37330278cdSJeff Kirsher #include <linux/kernel.h>
38330278cdSJeff Kirsher #include <linux/ptrace.h>
39330278cdSJeff Kirsher #include <linux/slab.h>
40330278cdSJeff Kirsher #include <linux/string.h>
41330278cdSJeff Kirsher #include <linux/timer.h>
42330278cdSJeff Kirsher #include <linux/delay.h>
43330278cdSJeff Kirsher #include <linux/module.h>
44330278cdSJeff Kirsher #include <linux/netdevice.h>
4526c6d281SJoe Perches #include <linux/io.h>
46330278cdSJeff Kirsher #include <pcmcia/cistpl.h>
47330278cdSJeff Kirsher #include <pcmcia/ds.h>
48330278cdSJeff Kirsher
4926c6d281SJoe Perches #include "arcdevice.h"
5026c6d281SJoe Perches #include "com20020.h"
51330278cdSJeff Kirsher
regdump(struct net_device * dev)52330278cdSJeff Kirsher static void regdump(struct net_device *dev)
53330278cdSJeff Kirsher {
54330278cdSJeff Kirsher #ifdef DEBUG
55330278cdSJeff Kirsher int ioaddr = dev->base_addr;
56330278cdSJeff Kirsher int count;
57330278cdSJeff Kirsher
58330278cdSJeff Kirsher netdev_dbg(dev, "register dump:\n");
590fec6513SJoe Perches for (count = 0; count < 16; count++) {
60330278cdSJeff Kirsher if (!(count % 16))
610fec6513SJoe Perches pr_cont("%04X:", ioaddr + count);
620fec6513SJoe Perches pr_cont(" %02X", arcnet_inb(ioaddr, count));
63330278cdSJeff Kirsher }
64330278cdSJeff Kirsher pr_cont("\n");
65330278cdSJeff Kirsher
66330278cdSJeff Kirsher netdev_dbg(dev, "buffer0 dump:\n");
67330278cdSJeff Kirsher /* set up the address register */
68330278cdSJeff Kirsher count = 0;
690fec6513SJoe Perches arcnet_outb((count >> 8) | RDDATAflag | AUTOINCflag,
707cfabe4fSTom Rix ioaddr, COM20020_REG_W_ADDR_HI);
710fec6513SJoe Perches arcnet_outb(count & 0xff, ioaddr, COM20020_REG_W_ADDR_LO);
72330278cdSJeff Kirsher
737f5e760cSJoe Perches for (count = 0; count < 256 + 32; count++) {
74330278cdSJeff Kirsher if (!(count % 16))
75330278cdSJeff Kirsher pr_cont("%04X:", count);
76330278cdSJeff Kirsher
77330278cdSJeff Kirsher /* copy the data */
780fec6513SJoe Perches pr_cont(" %02X", arcnet_inb(ioaddr, COM20020_REG_RW_MEMDATA));
79330278cdSJeff Kirsher }
80330278cdSJeff Kirsher pr_cont("\n");
81330278cdSJeff Kirsher #endif
82330278cdSJeff Kirsher }
83330278cdSJeff Kirsher
84330278cdSJeff Kirsher /*====================================================================*/
85330278cdSJeff Kirsher
86330278cdSJeff Kirsher /* Parameters that can be set with 'insmod' */
87330278cdSJeff Kirsher
88330278cdSJeff Kirsher static int node;
89330278cdSJeff Kirsher static int timeout = 3;
90330278cdSJeff Kirsher static int backplane;
91330278cdSJeff Kirsher static int clockp;
92330278cdSJeff Kirsher static int clockm;
93330278cdSJeff Kirsher
94330278cdSJeff Kirsher module_param(node, int, 0);
95330278cdSJeff Kirsher module_param(timeout, int, 0);
96330278cdSJeff Kirsher module_param(backplane, int, 0);
97330278cdSJeff Kirsher module_param(clockp, int, 0);
98330278cdSJeff Kirsher module_param(clockm, int, 0);
99330278cdSJeff Kirsher
100330278cdSJeff Kirsher MODULE_LICENSE("GPL");
101330278cdSJeff Kirsher
102330278cdSJeff Kirsher /*====================================================================*/
103330278cdSJeff Kirsher
104330278cdSJeff Kirsher static int com20020_config(struct pcmcia_device *link);
105330278cdSJeff Kirsher static void com20020_release(struct pcmcia_device *link);
106330278cdSJeff Kirsher
107330278cdSJeff Kirsher static void com20020_detach(struct pcmcia_device *p_dev);
108330278cdSJeff Kirsher
109330278cdSJeff Kirsher /*====================================================================*/
110330278cdSJeff Kirsher
com20020_probe(struct pcmcia_device * p_dev)111330278cdSJeff Kirsher static int com20020_probe(struct pcmcia_device *p_dev)
112330278cdSJeff Kirsher {
1132dfd2533SHimangi Saraogi struct com20020_dev *info;
114330278cdSJeff Kirsher struct net_device *dev;
115330278cdSJeff Kirsher struct arcnet_local *lp;
116*1c40cde6SWang Hai int ret = -ENOMEM;
117330278cdSJeff Kirsher
118330278cdSJeff Kirsher dev_dbg(&p_dev->dev, "com20020_attach()\n");
119330278cdSJeff Kirsher
120330278cdSJeff Kirsher /* Create new network device */
1212dfd2533SHimangi Saraogi info = kzalloc(sizeof(*info), GFP_KERNEL);
122330278cdSJeff Kirsher if (!info)
123330278cdSJeff Kirsher goto fail_alloc_info;
124330278cdSJeff Kirsher
125330278cdSJeff Kirsher dev = alloc_arcdev("");
126330278cdSJeff Kirsher if (!dev)
127330278cdSJeff Kirsher goto fail_alloc_dev;
128330278cdSJeff Kirsher
129330278cdSJeff Kirsher lp = netdev_priv(dev);
130330278cdSJeff Kirsher lp->timeout = timeout;
131330278cdSJeff Kirsher lp->backplane = backplane;
132330278cdSJeff Kirsher lp->clockp = clockp;
133330278cdSJeff Kirsher lp->clockm = clockm & 3;
134330278cdSJeff Kirsher lp->hw.owner = THIS_MODULE;
135330278cdSJeff Kirsher
136330278cdSJeff Kirsher /* fill in our module parameters as defaults */
13713b5ffa0SJakub Kicinski arcnet_set_addr(dev, node);
138330278cdSJeff Kirsher
139330278cdSJeff Kirsher p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
140330278cdSJeff Kirsher p_dev->resource[0]->end = 16;
141330278cdSJeff Kirsher p_dev->config_flags |= CONF_ENABLE_IRQ;
142330278cdSJeff Kirsher
143330278cdSJeff Kirsher info->dev = dev;
144330278cdSJeff Kirsher p_dev->priv = info;
145330278cdSJeff Kirsher
146*1c40cde6SWang Hai ret = com20020_config(p_dev);
147*1c40cde6SWang Hai if (ret)
148*1c40cde6SWang Hai goto fail_config;
149330278cdSJeff Kirsher
150*1c40cde6SWang Hai return 0;
151*1c40cde6SWang Hai
152*1c40cde6SWang Hai fail_config:
153*1c40cde6SWang Hai free_arcdev(dev);
154330278cdSJeff Kirsher fail_alloc_dev:
155330278cdSJeff Kirsher kfree(info);
156330278cdSJeff Kirsher fail_alloc_info:
157*1c40cde6SWang Hai return ret;
158330278cdSJeff Kirsher } /* com20020_attach */
159330278cdSJeff Kirsher
com20020_detach(struct pcmcia_device * link)160330278cdSJeff Kirsher static void com20020_detach(struct pcmcia_device *link)
161330278cdSJeff Kirsher {
1622dfd2533SHimangi Saraogi struct com20020_dev *info = link->priv;
163330278cdSJeff Kirsher struct net_device *dev = info->dev;
164330278cdSJeff Kirsher
165330278cdSJeff Kirsher dev_dbg(&link->dev, "detach...\n");
166330278cdSJeff Kirsher
167330278cdSJeff Kirsher dev_dbg(&link->dev, "com20020_detach\n");
168330278cdSJeff Kirsher
169330278cdSJeff Kirsher dev_dbg(&link->dev, "unregister...\n");
170330278cdSJeff Kirsher
171330278cdSJeff Kirsher unregister_netdev(dev);
172330278cdSJeff Kirsher
173f2f0a16bSJoe Perches /* this is necessary because we register our IRQ separately
174330278cdSJeff Kirsher * from card services.
175330278cdSJeff Kirsher */
176330278cdSJeff Kirsher if (dev->irq)
177330278cdSJeff Kirsher free_irq(dev->irq, dev);
178330278cdSJeff Kirsher
179330278cdSJeff Kirsher com20020_release(link);
180330278cdSJeff Kirsher
181330278cdSJeff Kirsher /* Unlink device structure, free bits */
182330278cdSJeff Kirsher dev_dbg(&link->dev, "unlinking...\n");
1837f5e760cSJoe Perches if (link->priv) {
184330278cdSJeff Kirsher dev = info->dev;
1857f5e760cSJoe Perches if (dev) {
186330278cdSJeff Kirsher dev_dbg(&link->dev, "kfree...\n");
18701365633SAhmed S. Darwish free_arcdev(dev);
188330278cdSJeff Kirsher }
189330278cdSJeff Kirsher dev_dbg(&link->dev, "kfree2...\n");
190330278cdSJeff Kirsher kfree(info);
191330278cdSJeff Kirsher }
192330278cdSJeff Kirsher
193330278cdSJeff Kirsher } /* com20020_detach */
194330278cdSJeff Kirsher
com20020_config(struct pcmcia_device * link)195330278cdSJeff Kirsher static int com20020_config(struct pcmcia_device *link)
196330278cdSJeff Kirsher {
197330278cdSJeff Kirsher struct arcnet_local *lp;
1982dfd2533SHimangi Saraogi struct com20020_dev *info;
199330278cdSJeff Kirsher struct net_device *dev;
200330278cdSJeff Kirsher int i, ret;
201330278cdSJeff Kirsher int ioaddr;
202330278cdSJeff Kirsher
203330278cdSJeff Kirsher info = link->priv;
204330278cdSJeff Kirsher dev = info->dev;
205330278cdSJeff Kirsher
206330278cdSJeff Kirsher dev_dbg(&link->dev, "config...\n");
207330278cdSJeff Kirsher
208330278cdSJeff Kirsher dev_dbg(&link->dev, "com20020_config\n");
209330278cdSJeff Kirsher
210330278cdSJeff Kirsher dev_dbg(&link->dev, "baseport1 is %Xh\n",
211330278cdSJeff Kirsher (unsigned int)link->resource[0]->start);
212330278cdSJeff Kirsher
213330278cdSJeff Kirsher i = -ENODEV;
214330278cdSJeff Kirsher link->io_lines = 16;
215330278cdSJeff Kirsher
2167f5e760cSJoe Perches if (!link->resource[0]->start) {
2177f5e760cSJoe Perches for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) {
218330278cdSJeff Kirsher link->resource[0]->start = ioaddr;
219330278cdSJeff Kirsher i = pcmcia_request_io(link);
220330278cdSJeff Kirsher if (i == 0)
221330278cdSJeff Kirsher break;
222330278cdSJeff Kirsher }
2237f5e760cSJoe Perches } else {
224330278cdSJeff Kirsher i = pcmcia_request_io(link);
2257f5e760cSJoe Perches }
226330278cdSJeff Kirsher
2277f5e760cSJoe Perches if (i != 0) {
228330278cdSJeff Kirsher dev_dbg(&link->dev, "requestIO failed totally!\n");
229330278cdSJeff Kirsher goto failed;
230330278cdSJeff Kirsher }
231330278cdSJeff Kirsher
232330278cdSJeff Kirsher ioaddr = dev->base_addr = link->resource[0]->start;
233330278cdSJeff Kirsher dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
234330278cdSJeff Kirsher
235330278cdSJeff Kirsher dev_dbg(&link->dev, "request IRQ %d\n",
236330278cdSJeff Kirsher link->irq);
2377f5e760cSJoe Perches if (!link->irq) {
238330278cdSJeff Kirsher dev_dbg(&link->dev, "requestIRQ failed totally!\n");
239330278cdSJeff Kirsher goto failed;
240330278cdSJeff Kirsher }
241330278cdSJeff Kirsher
242330278cdSJeff Kirsher dev->irq = link->irq;
243330278cdSJeff Kirsher
244330278cdSJeff Kirsher ret = pcmcia_enable_device(link);
245330278cdSJeff Kirsher if (ret)
246330278cdSJeff Kirsher goto failed;
247330278cdSJeff Kirsher
2487f5e760cSJoe Perches if (com20020_check(dev)) {
249330278cdSJeff Kirsher regdump(dev);
250330278cdSJeff Kirsher goto failed;
251330278cdSJeff Kirsher }
252330278cdSJeff Kirsher
253330278cdSJeff Kirsher lp = netdev_priv(dev);
254330278cdSJeff Kirsher lp->card_name = "PCMCIA COM20020";
255330278cdSJeff Kirsher lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
256330278cdSJeff Kirsher
257330278cdSJeff Kirsher SET_NETDEV_DEV(dev, &link->dev);
258330278cdSJeff Kirsher
259330278cdSJeff Kirsher i = com20020_found(dev, 0); /* calls register_netdev */
260330278cdSJeff Kirsher
261330278cdSJeff Kirsher if (i != 0) {
262330278cdSJeff Kirsher dev_notice(&link->dev,
263330278cdSJeff Kirsher "com20020_found() failed\n");
264330278cdSJeff Kirsher goto failed;
265330278cdSJeff Kirsher }
266330278cdSJeff Kirsher
267330278cdSJeff Kirsher netdev_dbg(dev, "port %#3lx, irq %d\n",
268330278cdSJeff Kirsher dev->base_addr, dev->irq);
269330278cdSJeff Kirsher return 0;
270330278cdSJeff Kirsher
271330278cdSJeff Kirsher failed:
272330278cdSJeff Kirsher dev_dbg(&link->dev, "com20020_config failed...\n");
273330278cdSJeff Kirsher com20020_release(link);
274330278cdSJeff Kirsher return -ENODEV;
275330278cdSJeff Kirsher } /* com20020_config */
276330278cdSJeff Kirsher
com20020_release(struct pcmcia_device * link)277330278cdSJeff Kirsher static void com20020_release(struct pcmcia_device *link)
278330278cdSJeff Kirsher {
279330278cdSJeff Kirsher dev_dbg(&link->dev, "com20020_release\n");
280330278cdSJeff Kirsher pcmcia_disable_device(link);
281330278cdSJeff Kirsher }
282330278cdSJeff Kirsher
com20020_suspend(struct pcmcia_device * link)283330278cdSJeff Kirsher static int com20020_suspend(struct pcmcia_device *link)
284330278cdSJeff Kirsher {
2852dfd2533SHimangi Saraogi struct com20020_dev *info = link->priv;
286330278cdSJeff Kirsher struct net_device *dev = info->dev;
287330278cdSJeff Kirsher
288330278cdSJeff Kirsher if (link->open)
289330278cdSJeff Kirsher netif_device_detach(dev);
290330278cdSJeff Kirsher
291330278cdSJeff Kirsher return 0;
292330278cdSJeff Kirsher }
293330278cdSJeff Kirsher
com20020_resume(struct pcmcia_device * link)294330278cdSJeff Kirsher static int com20020_resume(struct pcmcia_device *link)
295330278cdSJeff Kirsher {
2962dfd2533SHimangi Saraogi struct com20020_dev *info = link->priv;
297330278cdSJeff Kirsher struct net_device *dev = info->dev;
298330278cdSJeff Kirsher
299330278cdSJeff Kirsher if (link->open) {
300330278cdSJeff Kirsher int ioaddr = dev->base_addr;
301330278cdSJeff Kirsher struct arcnet_local *lp = netdev_priv(dev);
30201a1d5acSJoe Perches
3030fec6513SJoe Perches arcnet_outb(lp->config | 0x80, ioaddr, COM20020_REG_W_CONFIG);
3040fec6513SJoe Perches udelay(5);
3050fec6513SJoe Perches arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG);
306330278cdSJeff Kirsher }
307330278cdSJeff Kirsher
308330278cdSJeff Kirsher return 0;
309330278cdSJeff Kirsher }
310330278cdSJeff Kirsher
311330278cdSJeff Kirsher static const struct pcmcia_device_id com20020_ids[] = {
312330278cdSJeff Kirsher PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
313330278cdSJeff Kirsher "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
314330278cdSJeff Kirsher PCMCIA_DEVICE_PROD_ID12("SoHard AG",
315330278cdSJeff Kirsher "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
316330278cdSJeff Kirsher PCMCIA_DEVICE_NULL
317330278cdSJeff Kirsher };
318330278cdSJeff Kirsher MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
319330278cdSJeff Kirsher
320330278cdSJeff Kirsher static struct pcmcia_driver com20020_cs_driver = {
321330278cdSJeff Kirsher .owner = THIS_MODULE,
322330278cdSJeff Kirsher .name = "com20020_cs",
323330278cdSJeff Kirsher .probe = com20020_probe,
324330278cdSJeff Kirsher .remove = com20020_detach,
325330278cdSJeff Kirsher .id_table = com20020_ids,
326330278cdSJeff Kirsher .suspend = com20020_suspend,
327330278cdSJeff Kirsher .resume = com20020_resume,
328330278cdSJeff Kirsher };
329fdd3f29eSH Hartley Sweeten module_pcmcia_driver(com20020_cs_driver);
330