]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/net/pcmcia/com20020_cs.c
pcmcia: dev_node removal (drivers with unregister_netdev check)
[mirror_ubuntu-artful-kernel.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_types.h>
47 #include <pcmcia/cs.h>
48 #include <pcmcia/cistpl.h>
49 #include <pcmcia/ds.h>
50
51 #include <asm/io.h>
52 #include <asm/system.h>
53
54 #define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
55
56 #ifdef DEBUG
57
58 static void regdump(struct net_device *dev)
59 {
60 int ioaddr = dev->base_addr;
61 int count;
62
63 printk("com20020 register dump:\n");
64 for (count = ioaddr; count < ioaddr + 16; count++)
65 {
66 if (!(count % 16))
67 printk("\n%04X: ", count);
68 printk("%02X ", inb(count));
69 }
70 printk("\n");
71
72 printk("buffer0 dump:\n");
73 /* set up the address register */
74 count = 0;
75 outb((count >> 8) | RDDATAflag | AUTOINCflag, _ADDR_HI);
76 outb(count & 0xff, _ADDR_LO);
77
78 for (count = 0; count < 256+32; count++)
79 {
80 if (!(count % 16))
81 printk("\n%04X: ", count);
82
83 /* copy the data */
84 printk("%02X ", inb(_MEMDATA));
85 }
86 printk("\n");
87 }
88
89 #else
90
91 static inline void regdump(struct net_device *dev) { }
92
93 #endif
94
95
96 /*====================================================================*/
97
98 /* Parameters that can be set with 'insmod' */
99
100 static int node;
101 static int timeout = 3;
102 static int backplane;
103 static int clockp;
104 static int clockm;
105
106 module_param(node, int, 0);
107 module_param(timeout, int, 0);
108 module_param(backplane, int, 0);
109 module_param(clockp, int, 0);
110 module_param(clockm, int, 0);
111
112 MODULE_LICENSE("GPL");
113
114 /*====================================================================*/
115
116 static int com20020_config(struct pcmcia_device *link);
117 static void com20020_release(struct pcmcia_device *link);
118
119 static void com20020_detach(struct pcmcia_device *p_dev);
120
121 /*====================================================================*/
122
123 typedef struct com20020_dev_t {
124 struct net_device *dev;
125 } com20020_dev_t;
126
127 /*======================================================================
128
129 com20020_attach() creates an "instance" of the driver, allocating
130 local data structures for one device. The device is registered
131 with Card Services.
132
133 ======================================================================*/
134
135 static int com20020_probe(struct pcmcia_device *p_dev)
136 {
137 com20020_dev_t *info;
138 struct net_device *dev;
139 struct arcnet_local *lp;
140
141 dev_dbg(&p_dev->dev, "com20020_attach()\n");
142
143 /* Create new network device */
144 info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
145 if (!info)
146 goto fail_alloc_info;
147
148 dev = alloc_arcdev("");
149 if (!dev)
150 goto fail_alloc_dev;
151
152 lp = netdev_priv(dev);
153 lp->timeout = timeout;
154 lp->backplane = backplane;
155 lp->clockp = clockp;
156 lp->clockm = clockm & 3;
157 lp->hw.owner = THIS_MODULE;
158
159 /* fill in our module parameters as defaults */
160 dev->dev_addr[0] = node;
161
162 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
163 p_dev->io.NumPorts1 = 16;
164 p_dev->io.IOAddrLines = 16;
165 p_dev->conf.Attributes = CONF_ENABLE_IRQ;
166 p_dev->conf.IntType = INT_MEMORY_AND_IO;
167
168 info->dev = dev;
169 p_dev->priv = info;
170
171 return com20020_config(p_dev);
172
173 fail_alloc_dev:
174 kfree(info);
175 fail_alloc_info:
176 return -ENOMEM;
177 } /* com20020_attach */
178
179 /*======================================================================
180
181 This deletes a driver "instance". The device is de-registered
182 with Card Services. If it has been released, all local data
183 structures are freed. Otherwise, the structures will be freed
184 when the device is released.
185
186 ======================================================================*/
187
188 static void com20020_detach(struct pcmcia_device *link)
189 {
190 struct com20020_dev_t *info = link->priv;
191 struct net_device *dev = info->dev;
192
193 dev_dbg(&link->dev, "detach...\n");
194
195 dev_dbg(&link->dev, "com20020_detach\n");
196
197 dev_dbg(&link->dev, "unregister...\n");
198
199 unregister_netdev(dev);
200
201 /*
202 * this is necessary because we register our IRQ separately
203 * from card services.
204 */
205 if (dev->irq)
206 free_irq(dev->irq, dev);
207
208 com20020_release(link);
209
210 /* Unlink device structure, free bits */
211 dev_dbg(&link->dev, "unlinking...\n");
212 if (link->priv)
213 {
214 dev = info->dev;
215 if (dev)
216 {
217 dev_dbg(&link->dev, "kfree...\n");
218 free_netdev(dev);
219 }
220 dev_dbg(&link->dev, "kfree2...\n");
221 kfree(info);
222 }
223
224 } /* com20020_detach */
225
226 /*======================================================================
227
228 com20020_config() is scheduled to run after a CARD_INSERTION event
229 is received, to configure the PCMCIA socket, and to make the
230 device available to the system.
231
232 ======================================================================*/
233
234 static int com20020_config(struct pcmcia_device *link)
235 {
236 struct arcnet_local *lp;
237 com20020_dev_t *info;
238 struct net_device *dev;
239 int i, ret;
240 int ioaddr;
241
242 info = link->priv;
243 dev = info->dev;
244
245 dev_dbg(&link->dev, "config...\n");
246
247 dev_dbg(&link->dev, "com20020_config\n");
248
249 dev_dbg(&link->dev, "baseport1 is %Xh\n", link->io.BasePort1);
250 i = -ENODEV;
251 if (!link->io.BasePort1)
252 {
253 for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10)
254 {
255 link->io.BasePort1 = ioaddr;
256 i = pcmcia_request_io(link, &link->io);
257 if (i == 0)
258 break;
259 }
260 }
261 else
262 i = pcmcia_request_io(link, &link->io);
263
264 if (i != 0)
265 {
266 dev_dbg(&link->dev, "requestIO failed totally!\n");
267 goto failed;
268 }
269
270 ioaddr = dev->base_addr = link->io.BasePort1;
271 dev_dbg(&link->dev, "got ioaddr %Xh\n", ioaddr);
272
273 dev_dbg(&link->dev, "request IRQ %d\n",
274 link->irq);
275 if (!link->irq)
276 {
277 dev_dbg(&link->dev, "requestIRQ failed totally!\n");
278 goto failed;
279 }
280
281 dev->irq = link->irq;
282
283 ret = pcmcia_request_configuration(link, &link->conf);
284 if (ret)
285 goto failed;
286
287 if (com20020_check(dev))
288 {
289 regdump(dev);
290 goto failed;
291 }
292
293 lp = netdev_priv(dev);
294 lp->card_name = "PCMCIA COM20020";
295 lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */
296
297 SET_NETDEV_DEV(dev, &link->dev);
298
299 i = com20020_found(dev, 0); /* calls register_netdev */
300
301 if (i != 0) {
302 dev_printk(KERN_NOTICE, &link->dev,
303 "com20020_cs: com20020_found() failed\n");
304 goto failed;
305 }
306
307 dev_dbg(&link->dev,KERN_INFO "%s: port %#3lx, irq %d\n",
308 dev->name, dev->base_addr, dev->irq);
309 return 0;
310
311 failed:
312 dev_dbg(&link->dev, "com20020_config failed...\n");
313 com20020_release(link);
314 return -ENODEV;
315 } /* com20020_config */
316
317 /*======================================================================
318
319 After a card is removed, com20020_release() will unregister the net
320 device, and release the PCMCIA configuration. If the device is
321 still open, this will be postponed until it is closed.
322
323 ======================================================================*/
324
325 static void com20020_release(struct pcmcia_device *link)
326 {
327 dev_dbg(&link->dev, "com20020_release\n");
328 pcmcia_disable_device(link);
329 }
330
331 static int com20020_suspend(struct pcmcia_device *link)
332 {
333 com20020_dev_t *info = link->priv;
334 struct net_device *dev = info->dev;
335
336 if (link->open)
337 netif_device_detach(dev);
338
339 return 0;
340 }
341
342 static int com20020_resume(struct pcmcia_device *link)
343 {
344 com20020_dev_t *info = link->priv;
345 struct net_device *dev = info->dev;
346
347 if (link->open) {
348 int ioaddr = dev->base_addr;
349 struct arcnet_local *lp = netdev_priv(dev);
350 ARCRESET;
351 }
352
353 return 0;
354 }
355
356 static struct pcmcia_device_id com20020_ids[] = {
357 PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
358 "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
359 PCMCIA_DEVICE_PROD_ID12("SoHard AG",
360 "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
361 PCMCIA_DEVICE_NULL
362 };
363 MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
364
365 static struct pcmcia_driver com20020_cs_driver = {
366 .owner = THIS_MODULE,
367 .drv = {
368 .name = "com20020_cs",
369 },
370 .probe = com20020_probe,
371 .remove = com20020_detach,
372 .id_table = com20020_ids,
373 .suspend = com20020_suspend,
374 .resume = com20020_resume,
375 };
376
377 static int __init init_com20020_cs(void)
378 {
379 return pcmcia_register_driver(&com20020_cs_driver);
380 }
381
382 static void __exit exit_com20020_cs(void)
383 {
384 pcmcia_unregister_driver(&com20020_cs_driver);
385 }
386
387 module_init(init_com20020_cs);
388 module_exit(exit_com20020_cs);