Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[deliverable/linux.git] / drivers / net / pcmcia / com20020_cs.c
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
57 static 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
90 static inline void regdump(struct net_device *dev) { }
91
92 #endif
93
94
95 /*====================================================================*/
96
97 /* Parameters that can be set with 'insmod' */
98
99 static int node;
100 static int timeout = 3;
101 static int backplane;
102 static int clockp;
103 static int clockm;
104
105 module_param(node, int, 0);
106 module_param(timeout, int, 0);
107 module_param(backplane, int, 0);
108 module_param(clockp, int, 0);
109 module_param(clockm, int, 0);
110
111 MODULE_LICENSE("GPL");
112
113 /*====================================================================*/
114
115 static int com20020_config(struct pcmcia_device *link);
116 static void com20020_release(struct pcmcia_device *link);
117
118 static void com20020_detach(struct pcmcia_device *p_dev);
119
120 /*====================================================================*/
121
122 typedef 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
134 static 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
171 fail_alloc_dev:
172 kfree(info);
173 fail_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
186 static 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
232 static 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
313 failed:
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
327 static void com20020_release(struct pcmcia_device *link)
328 {
329 dev_dbg(&link->dev, "com20020_release\n");
330 pcmcia_disable_device(link);
331 }
332
333 static 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
344 static 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
358 static 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 };
365 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
366
367 static 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
379 static int __init init_com20020_cs(void)
380 {
381 return pcmcia_register_driver(&com20020_cs_driver);
382 }
383
384 static void __exit exit_com20020_cs(void)
385 {
386 pcmcia_unregister_driver(&com20020_cs_driver);
387 }
388
389 module_init(init_com20020_cs);
390 module_exit(exit_com20020_cs);
This page took 0.08075 seconds and 5 git commands to generate.