[PATCH] pcmcia: move event handler
[deliverable/linux.git] / drivers / net / pcmcia / ibmtr_cs.c
1 /*======================================================================
2
3 A PCMCIA token-ring driver for IBM-based cards
4
5 This driver supports the IBM PCMCIA Token-Ring Card.
6 Written by Steve Kipisz, kipisz@vnet.ibm.com or
7 bungy@ibm.net
8
9 Written 1995,1996.
10
11 This code is based on pcnet_cs.c from David Hinds.
12
13 V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
14
15 Linux V2.2.x presented significant changes to the underlying
16 ibmtr.c code. Mainly the code became a lot more organized and
17 modular.
18
19 This caused the old PCMCIA Token Ring driver to give up and go
20 home early. Instead of just patching the old code to make it
21 work, the PCMCIA code has been streamlined, updated and possibly
22 improved.
23
24 This code now only contains code required for the Card Services.
25 All we do here is set the card up enough so that the real ibmtr.c
26 driver can find it and work with it properly.
27
28 i.e. We set up the io port, irq, mmio memory and shared ram
29 memory. This enables ibmtr_probe in ibmtr.c to find the card and
30 configure it as though it was a normal ISA and/or PnP card.
31
32 CHANGES
33
34 v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
35 Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
36
37 v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
38 Updated to version 2.2.7 to match the first version of the kernel
39 that the modification to ibmtr.c were incorporated into.
40
41 v2.2.17 July 2000 Burt Silverman (burts@us.ibm.com)
42 Address translation feature of PCMCIA controller is usable so
43 memory windows can be placed in High memory (meaning above
44 0xFFFFF.)
45
46 ======================================================================*/
47
48 #include <linux/kernel.h>
49 #include <linux/init.h>
50 #include <linux/ptrace.h>
51 #include <linux/slab.h>
52 #include <linux/string.h>
53 #include <linux/timer.h>
54 #include <linux/module.h>
55 #include <linux/ethtool.h>
56 #include <linux/netdevice.h>
57 #include <linux/trdevice.h>
58 #include <linux/ibmtr.h>
59
60 #include <pcmcia/version.h>
61 #include <pcmcia/cs_types.h>
62 #include <pcmcia/cs.h>
63 #include <pcmcia/cistpl.h>
64 #include <pcmcia/ds.h>
65
66 #include <asm/uaccess.h>
67 #include <asm/io.h>
68 #include <asm/system.h>
69
70 #define PCMCIA
71 #include "../tokenring/ibmtr.c"
72
73 #ifdef PCMCIA_DEBUG
74 static int pc_debug = PCMCIA_DEBUG;
75 module_param(pc_debug, int, 0);
76 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
77 static char *version =
78 "ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
79 " 2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n"
80 " 2.4.2 2001/30/28 Midnight (Burt Silverman)\n";
81 #else
82 #define DEBUG(n, args...)
83 #endif
84
85 /*====================================================================*/
86
87 /* Parameters that can be set with 'insmod' */
88
89 /* MMIO base address */
90 static u_long mmiobase = 0xce000;
91
92 /* SRAM base address */
93 static u_long srambase = 0xd0000;
94
95 /* SRAM size 8,16,32,64 */
96 static u_long sramsize = 64;
97
98 /* Ringspeed 4,16 */
99 static int ringspeed = 16;
100
101 module_param(mmiobase, ulong, 0);
102 module_param(srambase, ulong, 0);
103 module_param(sramsize, ulong, 0);
104 module_param(ringspeed, int, 0);
105 MODULE_LICENSE("GPL");
106
107 /*====================================================================*/
108
109 static void ibmtr_config(dev_link_t *link);
110 static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase);
111 static void ibmtr_release(dev_link_t *link);
112 static int ibmtr_event(event_t event, int priority,
113 event_callback_args_t *args);
114
115 static dev_info_t dev_info = "ibmtr_cs";
116
117 static dev_link_t *ibmtr_attach(void);
118 static void ibmtr_detach(dev_link_t *);
119
120 static dev_link_t *dev_list;
121
122 /*====================================================================*/
123
124 typedef struct ibmtr_dev_t {
125 dev_link_t link;
126 struct net_device *dev;
127 dev_node_t node;
128 window_handle_t sram_win_handle;
129 struct tok_info *ti;
130 } ibmtr_dev_t;
131
132 static void netdev_get_drvinfo(struct net_device *dev,
133 struct ethtool_drvinfo *info)
134 {
135 strcpy(info->driver, "ibmtr_cs");
136 }
137
138 static struct ethtool_ops netdev_ethtool_ops = {
139 .get_drvinfo = netdev_get_drvinfo,
140 };
141
142 /*======================================================================
143
144 ibmtr_attach() creates an "instance" of the driver, allocating
145 local data structures for one device. The device is registered
146 with Card Services.
147
148 ======================================================================*/
149
150 static dev_link_t *ibmtr_attach(void)
151 {
152 ibmtr_dev_t *info;
153 dev_link_t *link;
154 struct net_device *dev;
155 client_reg_t client_reg;
156 int ret;
157
158 DEBUG(0, "ibmtr_attach()\n");
159
160 /* Create new token-ring device */
161 info = kmalloc(sizeof(*info), GFP_KERNEL);
162 if (!info) return NULL;
163 memset(info,0,sizeof(*info));
164 dev = alloc_trdev(sizeof(struct tok_info));
165 if (!dev) {
166 kfree(info);
167 return NULL;
168 }
169
170 link = &info->link;
171 link->priv = info;
172 info->ti = netdev_priv(dev);
173
174 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
175 link->io.NumPorts1 = 4;
176 link->io.IOAddrLines = 16;
177 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
178 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
179 link->irq.Handler = &tok_interrupt;
180 link->conf.Attributes = CONF_ENABLE_IRQ;
181 link->conf.Vcc = 50;
182 link->conf.IntType = INT_MEMORY_AND_IO;
183 link->conf.Present = PRESENT_OPTION;
184
185 link->irq.Instance = info->dev = dev;
186
187 SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
188
189 /* Register with Card Services */
190 link->next = dev_list;
191 dev_list = link;
192 client_reg.dev_info = &dev_info;
193 client_reg.Version = 0x0210;
194 client_reg.event_callback_args.client_data = link;
195 ret = pcmcia_register_client(&link->handle, &client_reg);
196 if (ret != 0) {
197 cs_error(link->handle, RegisterClient, ret);
198 goto out_detach;
199 }
200
201 out:
202 return link;
203
204 out_detach:
205 ibmtr_detach(link);
206 link = NULL;
207 goto out;
208 } /* ibmtr_attach */
209
210 /*======================================================================
211
212 This deletes a driver "instance". The device is de-registered
213 with Card Services. If it has been released, all local data
214 structures are freed. Otherwise, the structures will be freed
215 when the device is released.
216
217 ======================================================================*/
218
219 static void ibmtr_detach(dev_link_t *link)
220 {
221 struct ibmtr_dev_t *info = link->priv;
222 dev_link_t **linkp;
223 struct net_device *dev;
224
225 DEBUG(0, "ibmtr_detach(0x%p)\n", link);
226
227 /* Locate device structure */
228 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
229 if (*linkp == link) break;
230 if (*linkp == NULL)
231 return;
232
233 dev = info->dev;
234
235 if (link->dev)
236 unregister_netdev(dev);
237
238 {
239 struct tok_info *ti = netdev_priv(dev);
240 del_timer_sync(&(ti->tr_timer));
241 }
242 if (link->state & DEV_CONFIG)
243 ibmtr_release(link);
244
245 if (link->handle)
246 pcmcia_deregister_client(link->handle);
247
248 /* Unlink device structure, free bits */
249 *linkp = link->next;
250 free_netdev(dev);
251 kfree(info);
252 } /* ibmtr_detach */
253
254 /*======================================================================
255
256 ibmtr_config() is scheduled to run after a CARD_INSERTION event
257 is received, to configure the PCMCIA socket, and to make the
258 token-ring device available to the system.
259
260 ======================================================================*/
261
262 #define CS_CHECK(fn, ret) \
263 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
264
265 static void ibmtr_config(dev_link_t *link)
266 {
267 client_handle_t handle = link->handle;
268 ibmtr_dev_t *info = link->priv;
269 struct net_device *dev = info->dev;
270 struct tok_info *ti = netdev_priv(dev);
271 tuple_t tuple;
272 cisparse_t parse;
273 win_req_t req;
274 memreq_t mem;
275 int i, last_ret, last_fn;
276 u_char buf[64];
277
278 DEBUG(0, "ibmtr_config(0x%p)\n", link);
279
280 tuple.Attributes = 0;
281 tuple.TupleData = buf;
282 tuple.TupleDataMax = 64;
283 tuple.TupleOffset = 0;
284 tuple.DesiredTuple = CISTPL_CONFIG;
285 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
286 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
287 CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
288 link->conf.ConfigBase = parse.config.base;
289
290 /* Configure card */
291 link->state |= DEV_CONFIG;
292
293 link->conf.ConfigIndex = 0x61;
294
295 /* Determine if this is PRIMARY or ALTERNATE. */
296
297 /* Try PRIMARY card at 0xA20-0xA23 */
298 link->io.BasePort1 = 0xA20;
299 i = pcmcia_request_io(link->handle, &link->io);
300 if (i != CS_SUCCESS) {
301 /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
302 link->io.BasePort1 = 0xA24;
303 CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
304 }
305 dev->base_addr = link->io.BasePort1;
306
307 CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
308 dev->irq = link->irq.AssignedIRQ;
309 ti->irq = link->irq.AssignedIRQ;
310 ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
311
312 /* Allocate the MMIO memory window */
313 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
314 req.Attributes |= WIN_USE_WAIT;
315 req.Base = 0;
316 req.Size = 0x2000;
317 req.AccessSpeed = 250;
318 CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win));
319
320 mem.CardOffset = mmiobase;
321 mem.Page = 0;
322 CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
323 ti->mmio = ioremap(req.Base, req.Size);
324
325 /* Allocate the SRAM memory window */
326 req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
327 req.Attributes |= WIN_USE_WAIT;
328 req.Base = 0;
329 req.Size = sramsize * 1024;
330 req.AccessSpeed = 250;
331 CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &info->sram_win_handle));
332
333 mem.CardOffset = srambase;
334 mem.Page = 0;
335 CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem));
336
337 ti->sram_base = mem.CardOffset >> 12;
338 ti->sram_virt = ioremap(req.Base, req.Size);
339 ti->sram_phys = req.Base;
340
341 CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
342
343 /* Set up the Token-Ring Controller Configuration Register and
344 turn on the card. Check the "Local Area Network Credit Card
345 Adapters Technical Reference" SC30-3585 for this info. */
346 ibmtr_hw_setup(dev, mmiobase);
347
348 link->dev = &info->node;
349 link->state &= ~DEV_CONFIG_PENDING;
350 SET_NETDEV_DEV(dev, &handle_to_dev(handle));
351
352 i = ibmtr_probe_card(dev);
353 if (i != 0) {
354 printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
355 link->dev = NULL;
356 goto failed;
357 }
358
359 strcpy(info->node.dev_name, dev->name);
360
361 printk(KERN_INFO "%s: port %#3lx, irq %d,",
362 dev->name, dev->base_addr, dev->irq);
363 printk (" mmio %#5lx,", (u_long)ti->mmio);
364 printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
365 printk ("\n" KERN_INFO " hwaddr=");
366 for (i = 0; i < TR_ALEN; i++)
367 printk("%02X", dev->dev_addr[i]);
368 printk("\n");
369 return;
370
371 cs_failed:
372 cs_error(link->handle, last_fn, last_ret);
373 failed:
374 ibmtr_release(link);
375 } /* ibmtr_config */
376
377 /*======================================================================
378
379 After a card is removed, ibmtr_release() will unregister the net
380 device, and release the PCMCIA configuration. If the device is
381 still open, this will be postponed until it is closed.
382
383 ======================================================================*/
384
385 static void ibmtr_release(dev_link_t *link)
386 {
387 ibmtr_dev_t *info = link->priv;
388 struct net_device *dev = info->dev;
389
390 DEBUG(0, "ibmtr_release(0x%p)\n", link);
391
392 pcmcia_release_configuration(link->handle);
393 pcmcia_release_io(link->handle, &link->io);
394 pcmcia_release_irq(link->handle, &link->irq);
395 if (link->win) {
396 struct tok_info *ti = netdev_priv(dev);
397 iounmap(ti->mmio);
398 pcmcia_release_window(link->win);
399 pcmcia_release_window(info->sram_win_handle);
400 }
401
402 link->state &= ~DEV_CONFIG;
403 }
404
405 /*======================================================================
406
407 The card status event handler. Mostly, this schedules other
408 stuff to run after an event is received. A CARD_REMOVAL event
409 also sets some flags to discourage the net drivers from trying
410 to talk to the card any more.
411
412 ======================================================================*/
413
414 static int ibmtr_event(event_t event, int priority,
415 event_callback_args_t *args)
416 {
417 dev_link_t *link = args->client_data;
418 ibmtr_dev_t *info = link->priv;
419 struct net_device *dev = info->dev;
420
421 DEBUG(1, "ibmtr_event(0x%06x)\n", event);
422
423 switch (event) {
424 case CS_EVENT_CARD_REMOVAL:
425 link->state &= ~DEV_PRESENT;
426 if (link->state & DEV_CONFIG) {
427 /* set flag to bypass normal interrupt code */
428 struct tok_info *priv = netdev_priv(dev);
429 priv->sram_phys |= 1;
430 netif_device_detach(dev);
431 }
432 break;
433 case CS_EVENT_CARD_INSERTION:
434 link->state |= DEV_PRESENT;
435 ibmtr_config(link);
436 break;
437 case CS_EVENT_PM_SUSPEND:
438 link->state |= DEV_SUSPEND;
439 /* Fall through... */
440 case CS_EVENT_RESET_PHYSICAL:
441 if (link->state & DEV_CONFIG) {
442 if (link->open)
443 netif_device_detach(dev);
444 pcmcia_release_configuration(link->handle);
445 }
446 break;
447 case CS_EVENT_PM_RESUME:
448 link->state &= ~DEV_SUSPEND;
449 /* Fall through... */
450 case CS_EVENT_CARD_RESET:
451 if (link->state & DEV_CONFIG) {
452 pcmcia_request_configuration(link->handle, &link->conf);
453 if (link->open) {
454 ibmtr_probe(dev); /* really? */
455 netif_device_attach(dev);
456 }
457 }
458 break;
459 }
460 return 0;
461 } /* ibmtr_event */
462
463 /*====================================================================*/
464
465 static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
466 {
467 int i;
468
469 /* Bizarre IBM behavior, there are 16 bits of information we
470 need to set, but the card only allows us to send 4 bits at a
471 time. For each byte sent to base_addr, bits 7-4 tell the
472 card which part of the 16 bits we are setting, bits 3-0 contain
473 the actual information */
474
475 /* First nibble provides 4 bits of mmio */
476 i = (mmiobase >> 16) & 0x0F;
477 outb(i, dev->base_addr);
478
479 /* Second nibble provides 3 bits of mmio */
480 i = 0x10 | ((mmiobase >> 12) & 0x0E);
481 outb(i, dev->base_addr);
482
483 /* Third nibble, hard-coded values */
484 i = 0x26;
485 outb(i, dev->base_addr);
486
487 /* Fourth nibble sets shared ram page size */
488
489 /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
490 i = (sramsize >> 4) & 0x07;
491 i = ((i == 4) ? 3 : i) << 2;
492 i |= 0x30;
493
494 if (ringspeed == 16)
495 i |= 2;
496 if (dev->base_addr == 0xA24)
497 i |= 1;
498 outb(i, dev->base_addr);
499
500 /* 0x40 will release the card for use */
501 outb(0x40, dev->base_addr);
502
503 return;
504 }
505
506 static struct pcmcia_device_id ibmtr_ids[] = {
507 PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
508 PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
509 PCMCIA_DEVICE_NULL,
510 };
511 MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
512
513 static struct pcmcia_driver ibmtr_cs_driver = {
514 .owner = THIS_MODULE,
515 .drv = {
516 .name = "ibmtr_cs",
517 },
518 .attach = ibmtr_attach,
519 .event = ibmtr_event,
520 .detach = ibmtr_detach,
521 .id_table = ibmtr_ids,
522 };
523
524 static int __init init_ibmtr_cs(void)
525 {
526 return pcmcia_register_driver(&ibmtr_cs_driver);
527 }
528
529 static void __exit exit_ibmtr_cs(void)
530 {
531 pcmcia_unregister_driver(&ibmtr_cs_driver);
532 BUG_ON(dev_list != NULL);
533 }
534
535 module_init(init_ibmtr_cs);
536 module_exit(exit_ibmtr_cs);
This page took 0.042483 seconds and 5 git commands to generate.