• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/net/pcmcia/
1/*
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
46#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
55#ifdef DEBUG
56
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
90static 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
115static int com20020_config(struct pcmcia_device *link);
116static void com20020_release(struct pcmcia_device *link);
117
118static void com20020_detach(struct pcmcia_device *p_dev);
119
120/*====================================================================*/
121
122typedef struct com20020_dev_t {
123    struct net_device       *dev;
124} 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
134static int com20020_probe(struct pcmcia_device *p_dev)
135{
136    com20020_dev_t *info;
137    struct net_device *dev;
138    struct arcnet_local *lp;
139
140    dev_dbg(&p_dev->dev, "com20020_attach()\n");
141
142    /* Create new network device */
143    info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
144    if (!info)
145	goto fail_alloc_info;
146
147    dev = alloc_arcdev("");
148    if (!dev)
149	goto fail_alloc_dev;
150
151    lp = netdev_priv(dev);
152    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
161    p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
162    p_dev->resource[0]->end = 16;
163    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
164    p_dev->conf.IntType = INT_MEMORY_AND_IO;
165
166    info->dev = dev;
167    p_dev->priv = info;
168
169    return com20020_config(p_dev);
170
171fail_alloc_dev:
172    kfree(info);
173fail_alloc_info:
174    return -ENOMEM;
175} /* 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
186static void com20020_detach(struct pcmcia_device *link)
187{
188    struct com20020_dev_t *info = link->priv;
189    struct net_device *dev = info->dev;
190
191    dev_dbg(&link->dev, "detach...\n");
192
193    dev_dbg(&link->dev, "com20020_detach\n");
194
195    dev_dbg(&link->dev, "unregister...\n");
196
197    unregister_netdev(dev);
198
199    /*
200     * this is necessary because we register our IRQ separately
201     * from card services.
202     */
203    if (dev->irq)
204	    free_irq(dev->irq, dev);
205
206    com20020_release(link);
207
208    /* Unlink device structure, free bits */
209    dev_dbg(&link->dev, "unlinking...\n");
210    if (link->priv)
211    {
212	dev = info->dev;
213	if (dev)
214	{
215	    dev_dbg(&link->dev, "kfree...\n");
216	    free_netdev(dev);
217	}
218	dev_dbg(&link->dev, "kfree2...\n");
219	kfree(info);
220    }
221
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
232static int com20020_config(struct pcmcia_device *link)
233{
234    struct arcnet_local *lp;
235    com20020_dev_t *info;
236    struct net_device *dev;
237    int i, ret;
238    int ioaddr;
239
240    info = link->priv;
241    dev = info->dev;
242
243    dev_dbg(&link->dev, "config...\n");
244
245    dev_dbg(&link->dev, "com20020_config\n");
246
247    dev_dbg(&link->dev, "baseport1 is %Xh\n",
248	    (unsigned int) link->resource[0]->start);
249
250    i = -ENODEV;
251    link->io_lines = 16;
252
253    if (!link->resource[0]->start)
254    {
255	for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
256	{
257	    link->resource[0]->start = ioaddr;
258	    i = pcmcia_request_io(link);
259	    if (i == 0)
260		break;
261	}
262    }
263    else
264	i = pcmcia_request_io(link);
265
266    if (i != 0)
267    {
268	dev_dbg(&link->dev, "requestIO failed totally!\n");
269	goto failed;
270    }
271
272    ioaddr = dev->base_addr = link->resource[0]->start;
273    dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
274
275    dev_dbg(&link->dev, "request IRQ %d\n",
276	    link->irq);
277    if (!link->irq)
278    {
279	dev_dbg(&link->dev, "requestIRQ failed totally!\n");
280	goto failed;
281    }
282
283    dev->irq = link->irq;
284
285    ret = pcmcia_request_configuration(link, &link->conf);
286    if (ret)
287	    goto failed;
288
289    if (com20020_check(dev))
290    {
291	regdump(dev);
292	goto failed;
293    }
294
295    lp = netdev_priv(dev);
296    lp->card_name = "PCMCIA COM20020";
297    lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
298
299    SET_NETDEV_DEV(dev, &link->dev);
300
301    i = com20020_found(dev, 0);	/* calls register_netdev */
302
303    if (i != 0) {
304	dev_printk(KERN_NOTICE, &link->dev,
305		"com20020_cs: com20020_found() failed\n");
306	goto failed;
307    }
308
309    dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
310           dev->name, dev->base_addr, dev->irq);
311    return 0;
312
313failed:
314    dev_dbg(&link->dev, "com20020_config failed...\n");
315    com20020_release(link);
316    return -ENODEV;
317} /* 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
327static void com20020_release(struct pcmcia_device *link)
328{
329	dev_dbg(&link->dev, "com20020_release\n");
330	pcmcia_disable_device(link);
331}
332
333static int com20020_suspend(struct pcmcia_device *link)
334{
335	com20020_dev_t *info = link->priv;
336	struct net_device *dev = info->dev;
337
338	if (link->open)
339		netif_device_detach(dev);
340
341	return 0;
342}
343
344static int com20020_resume(struct pcmcia_device *link)
345{
346	com20020_dev_t *info = link->priv;
347	struct net_device *dev = info->dev;
348
349	if (link->open) {
350		int ioaddr = dev->base_addr;
351		struct arcnet_local *lp = netdev_priv(dev);
352		ARCRESET;
353	}
354
355	return 0;
356}
357
358static struct pcmcia_device_id com20020_ids[] = {
359	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),
363	PCMCIA_DEVICE_NULL
364};
365MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
366
367static struct pcmcia_driver com20020_cs_driver = {
368	.owner		= THIS_MODULE,
369	.drv		= {
370		.name	= "com20020_cs",
371	},
372	.probe		= com20020_probe,
373	.remove		= com20020_detach,
374	.id_table	= com20020_ids,
375	.suspend	= com20020_suspend,
376	.resume		= com20020_resume,
377};
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);
387}
388
389module_init(init_com20020_cs);
390module_exit(exit_com20020_cs);
391