diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/pcmcia/ibmtr_cs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/net/pcmcia/ibmtr_cs.c')
-rw-r--r-- | drivers/net/pcmcia/ibmtr_cs.c | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c new file mode 100644 index 000000000000..3107ccfe8f3d --- /dev/null +++ b/drivers/net/pcmcia/ibmtr_cs.c | |||
@@ -0,0 +1,535 @@ | |||
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 | extern int ibmtr_probe_card(struct net_device *dev); | ||
123 | extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs); | ||
124 | |||
125 | /*====================================================================*/ | ||
126 | |||
127 | typedef struct ibmtr_dev_t { | ||
128 | dev_link_t link; | ||
129 | struct net_device *dev; | ||
130 | dev_node_t node; | ||
131 | window_handle_t sram_win_handle; | ||
132 | struct tok_info *ti; | ||
133 | } ibmtr_dev_t; | ||
134 | |||
135 | static void netdev_get_drvinfo(struct net_device *dev, | ||
136 | struct ethtool_drvinfo *info) | ||
137 | { | ||
138 | strcpy(info->driver, "ibmtr_cs"); | ||
139 | } | ||
140 | |||
141 | static struct ethtool_ops netdev_ethtool_ops = { | ||
142 | .get_drvinfo = netdev_get_drvinfo, | ||
143 | }; | ||
144 | |||
145 | /*====================================================================== | ||
146 | |||
147 | ibmtr_attach() creates an "instance" of the driver, allocating | ||
148 | local data structures for one device. The device is registered | ||
149 | with Card Services. | ||
150 | |||
151 | ======================================================================*/ | ||
152 | |||
153 | static dev_link_t *ibmtr_attach(void) | ||
154 | { | ||
155 | ibmtr_dev_t *info; | ||
156 | dev_link_t *link; | ||
157 | struct net_device *dev; | ||
158 | client_reg_t client_reg; | ||
159 | int ret; | ||
160 | |||
161 | DEBUG(0, "ibmtr_attach()\n"); | ||
162 | |||
163 | /* Create new token-ring device */ | ||
164 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
165 | if (!info) return NULL; | ||
166 | memset(info,0,sizeof(*info)); | ||
167 | dev = alloc_trdev(sizeof(struct tok_info)); | ||
168 | if (!dev) { | ||
169 | kfree(info); | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | link = &info->link; | ||
174 | link->priv = info; | ||
175 | info->ti = netdev_priv(dev); | ||
176 | |||
177 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | ||
178 | link->io.NumPorts1 = 4; | ||
179 | link->io.IOAddrLines = 16; | ||
180 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; | ||
181 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | ||
182 | link->irq.Handler = &tok_interrupt; | ||
183 | link->conf.Attributes = CONF_ENABLE_IRQ; | ||
184 | link->conf.Vcc = 50; | ||
185 | link->conf.IntType = INT_MEMORY_AND_IO; | ||
186 | link->conf.Present = PRESENT_OPTION; | ||
187 | |||
188 | link->irq.Instance = info->dev = dev; | ||
189 | |||
190 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | ||
191 | |||
192 | /* Register with Card Services */ | ||
193 | link->next = dev_list; | ||
194 | dev_list = link; | ||
195 | client_reg.dev_info = &dev_info; | ||
196 | client_reg.EventMask = | ||
197 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
198 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
199 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
200 | client_reg.event_handler = &ibmtr_event; | ||
201 | client_reg.Version = 0x0210; | ||
202 | client_reg.event_callback_args.client_data = link; | ||
203 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
204 | if (ret != 0) { | ||
205 | cs_error(link->handle, RegisterClient, ret); | ||
206 | goto out_detach; | ||
207 | } | ||
208 | |||
209 | out: | ||
210 | return link; | ||
211 | |||
212 | out_detach: | ||
213 | ibmtr_detach(link); | ||
214 | link = NULL; | ||
215 | goto out; | ||
216 | } /* ibmtr_attach */ | ||
217 | |||
218 | /*====================================================================== | ||
219 | |||
220 | This deletes a driver "instance". The device is de-registered | ||
221 | with Card Services. If it has been released, all local data | ||
222 | structures are freed. Otherwise, the structures will be freed | ||
223 | when the device is released. | ||
224 | |||
225 | ======================================================================*/ | ||
226 | |||
227 | static void ibmtr_detach(dev_link_t *link) | ||
228 | { | ||
229 | struct ibmtr_dev_t *info = link->priv; | ||
230 | dev_link_t **linkp; | ||
231 | struct net_device *dev; | ||
232 | |||
233 | DEBUG(0, "ibmtr_detach(0x%p)\n", link); | ||
234 | |||
235 | /* Locate device structure */ | ||
236 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
237 | if (*linkp == link) break; | ||
238 | if (*linkp == NULL) | ||
239 | return; | ||
240 | |||
241 | dev = info->dev; | ||
242 | |||
243 | if (link->dev) | ||
244 | unregister_netdev(dev); | ||
245 | |||
246 | { | ||
247 | struct tok_info *ti = netdev_priv(dev); | ||
248 | del_timer_sync(&(ti->tr_timer)); | ||
249 | } | ||
250 | if (link->state & DEV_CONFIG) | ||
251 | ibmtr_release(link); | ||
252 | |||
253 | if (link->handle) | ||
254 | pcmcia_deregister_client(link->handle); | ||
255 | |||
256 | /* Unlink device structure, free bits */ | ||
257 | *linkp = link->next; | ||
258 | free_netdev(dev); | ||
259 | kfree(info); | ||
260 | } /* ibmtr_detach */ | ||
261 | |||
262 | /*====================================================================== | ||
263 | |||
264 | ibmtr_config() is scheduled to run after a CARD_INSERTION event | ||
265 | is received, to configure the PCMCIA socket, and to make the | ||
266 | token-ring device available to the system. | ||
267 | |||
268 | ======================================================================*/ | ||
269 | |||
270 | #define CS_CHECK(fn, ret) \ | ||
271 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | ||
272 | |||
273 | static void ibmtr_config(dev_link_t *link) | ||
274 | { | ||
275 | client_handle_t handle = link->handle; | ||
276 | ibmtr_dev_t *info = link->priv; | ||
277 | struct net_device *dev = info->dev; | ||
278 | struct tok_info *ti = netdev_priv(dev); | ||
279 | tuple_t tuple; | ||
280 | cisparse_t parse; | ||
281 | win_req_t req; | ||
282 | memreq_t mem; | ||
283 | int i, last_ret, last_fn; | ||
284 | u_char buf[64]; | ||
285 | |||
286 | DEBUG(0, "ibmtr_config(0x%p)\n", link); | ||
287 | |||
288 | tuple.Attributes = 0; | ||
289 | tuple.TupleData = buf; | ||
290 | tuple.TupleDataMax = 64; | ||
291 | tuple.TupleOffset = 0; | ||
292 | tuple.DesiredTuple = CISTPL_CONFIG; | ||
293 | CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); | ||
294 | CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); | ||
295 | CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); | ||
296 | link->conf.ConfigBase = parse.config.base; | ||
297 | |||
298 | /* Configure card */ | ||
299 | link->state |= DEV_CONFIG; | ||
300 | |||
301 | link->conf.ConfigIndex = 0x61; | ||
302 | |||
303 | /* Determine if this is PRIMARY or ALTERNATE. */ | ||
304 | |||
305 | /* Try PRIMARY card at 0xA20-0xA23 */ | ||
306 | link->io.BasePort1 = 0xA20; | ||
307 | i = pcmcia_request_io(link->handle, &link->io); | ||
308 | if (i != CS_SUCCESS) { | ||
309 | /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ | ||
310 | link->io.BasePort1 = 0xA24; | ||
311 | CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); | ||
312 | } | ||
313 | dev->base_addr = link->io.BasePort1; | ||
314 | |||
315 | CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); | ||
316 | dev->irq = link->irq.AssignedIRQ; | ||
317 | ti->irq = link->irq.AssignedIRQ; | ||
318 | ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); | ||
319 | |||
320 | /* Allocate the MMIO memory window */ | ||
321 | req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; | ||
322 | req.Attributes |= WIN_USE_WAIT; | ||
323 | req.Base = 0; | ||
324 | req.Size = 0x2000; | ||
325 | req.AccessSpeed = 250; | ||
326 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); | ||
327 | |||
328 | mem.CardOffset = mmiobase; | ||
329 | mem.Page = 0; | ||
330 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); | ||
331 | ti->mmio = ioremap(req.Base, req.Size); | ||
332 | |||
333 | /* Allocate the SRAM memory window */ | ||
334 | req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; | ||
335 | req.Attributes |= WIN_USE_WAIT; | ||
336 | req.Base = 0; | ||
337 | req.Size = sramsize * 1024; | ||
338 | req.AccessSpeed = 250; | ||
339 | CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &info->sram_win_handle)); | ||
340 | |||
341 | mem.CardOffset = srambase; | ||
342 | mem.Page = 0; | ||
343 | CS_CHECK(MapMemPage, pcmcia_map_mem_page(info->sram_win_handle, &mem)); | ||
344 | |||
345 | ti->sram_base = mem.CardOffset >> 12; | ||
346 | ti->sram_virt = ioremap(req.Base, req.Size); | ||
347 | ti->sram_phys = req.Base; | ||
348 | |||
349 | CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); | ||
350 | |||
351 | /* Set up the Token-Ring Controller Configuration Register and | ||
352 | turn on the card. Check the "Local Area Network Credit Card | ||
353 | Adapters Technical Reference" SC30-3585 for this info. */ | ||
354 | ibmtr_hw_setup(dev, mmiobase); | ||
355 | |||
356 | link->dev = &info->node; | ||
357 | link->state &= ~DEV_CONFIG_PENDING; | ||
358 | SET_NETDEV_DEV(dev, &handle_to_dev(handle)); | ||
359 | |||
360 | i = ibmtr_probe_card(dev); | ||
361 | if (i != 0) { | ||
362 | printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); | ||
363 | link->dev = NULL; | ||
364 | goto failed; | ||
365 | } | ||
366 | |||
367 | strcpy(info->node.dev_name, dev->name); | ||
368 | |||
369 | printk(KERN_INFO "%s: port %#3lx, irq %d,", | ||
370 | dev->name, dev->base_addr, dev->irq); | ||
371 | printk (" mmio %#5lx,", (u_long)ti->mmio); | ||
372 | printk (" sram %#5lx,", (u_long)ti->sram_base << 12); | ||
373 | printk ("\n" KERN_INFO " hwaddr="); | ||
374 | for (i = 0; i < TR_ALEN; i++) | ||
375 | printk("%02X", dev->dev_addr[i]); | ||
376 | printk("\n"); | ||
377 | return; | ||
378 | |||
379 | cs_failed: | ||
380 | cs_error(link->handle, last_fn, last_ret); | ||
381 | failed: | ||
382 | ibmtr_release(link); | ||
383 | } /* ibmtr_config */ | ||
384 | |||
385 | /*====================================================================== | ||
386 | |||
387 | After a card is removed, ibmtr_release() will unregister the net | ||
388 | device, and release the PCMCIA configuration. If the device is | ||
389 | still open, this will be postponed until it is closed. | ||
390 | |||
391 | ======================================================================*/ | ||
392 | |||
393 | static void ibmtr_release(dev_link_t *link) | ||
394 | { | ||
395 | ibmtr_dev_t *info = link->priv; | ||
396 | struct net_device *dev = info->dev; | ||
397 | |||
398 | DEBUG(0, "ibmtr_release(0x%p)\n", link); | ||
399 | |||
400 | pcmcia_release_configuration(link->handle); | ||
401 | pcmcia_release_io(link->handle, &link->io); | ||
402 | pcmcia_release_irq(link->handle, &link->irq); | ||
403 | if (link->win) { | ||
404 | struct tok_info *ti = netdev_priv(dev); | ||
405 | iounmap(ti->mmio); | ||
406 | pcmcia_release_window(link->win); | ||
407 | pcmcia_release_window(info->sram_win_handle); | ||
408 | } | ||
409 | |||
410 | link->state &= ~DEV_CONFIG; | ||
411 | } | ||
412 | |||
413 | /*====================================================================== | ||
414 | |||
415 | The card status event handler. Mostly, this schedules other | ||
416 | stuff to run after an event is received. A CARD_REMOVAL event | ||
417 | also sets some flags to discourage the net drivers from trying | ||
418 | to talk to the card any more. | ||
419 | |||
420 | ======================================================================*/ | ||
421 | |||
422 | static int ibmtr_event(event_t event, int priority, | ||
423 | event_callback_args_t *args) | ||
424 | { | ||
425 | dev_link_t *link = args->client_data; | ||
426 | ibmtr_dev_t *info = link->priv; | ||
427 | struct net_device *dev = info->dev; | ||
428 | |||
429 | DEBUG(1, "ibmtr_event(0x%06x)\n", event); | ||
430 | |||
431 | switch (event) { | ||
432 | case CS_EVENT_CARD_REMOVAL: | ||
433 | link->state &= ~DEV_PRESENT; | ||
434 | if (link->state & DEV_CONFIG) { | ||
435 | /* set flag to bypass normal interrupt code */ | ||
436 | struct tok_info *priv = netdev_priv(dev); | ||
437 | priv->sram_phys |= 1; | ||
438 | netif_device_detach(dev); | ||
439 | } | ||
440 | break; | ||
441 | case CS_EVENT_CARD_INSERTION: | ||
442 | link->state |= DEV_PRESENT; | ||
443 | ibmtr_config(link); | ||
444 | break; | ||
445 | case CS_EVENT_PM_SUSPEND: | ||
446 | link->state |= DEV_SUSPEND; | ||
447 | /* Fall through... */ | ||
448 | case CS_EVENT_RESET_PHYSICAL: | ||
449 | if (link->state & DEV_CONFIG) { | ||
450 | if (link->open) | ||
451 | netif_device_detach(dev); | ||
452 | pcmcia_release_configuration(link->handle); | ||
453 | } | ||
454 | break; | ||
455 | case CS_EVENT_PM_RESUME: | ||
456 | link->state &= ~DEV_SUSPEND; | ||
457 | /* Fall through... */ | ||
458 | case CS_EVENT_CARD_RESET: | ||
459 | if (link->state & DEV_CONFIG) { | ||
460 | pcmcia_request_configuration(link->handle, &link->conf); | ||
461 | if (link->open) { | ||
462 | ibmtr_probe(dev); /* really? */ | ||
463 | netif_device_attach(dev); | ||
464 | } | ||
465 | } | ||
466 | break; | ||
467 | } | ||
468 | return 0; | ||
469 | } /* ibmtr_event */ | ||
470 | |||
471 | /*====================================================================*/ | ||
472 | |||
473 | static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) | ||
474 | { | ||
475 | int i; | ||
476 | |||
477 | /* Bizarre IBM behavior, there are 16 bits of information we | ||
478 | need to set, but the card only allows us to send 4 bits at a | ||
479 | time. For each byte sent to base_addr, bits 7-4 tell the | ||
480 | card which part of the 16 bits we are setting, bits 3-0 contain | ||
481 | the actual information */ | ||
482 | |||
483 | /* First nibble provides 4 bits of mmio */ | ||
484 | i = (mmiobase >> 16) & 0x0F; | ||
485 | outb(i, dev->base_addr); | ||
486 | |||
487 | /* Second nibble provides 3 bits of mmio */ | ||
488 | i = 0x10 | ((mmiobase >> 12) & 0x0E); | ||
489 | outb(i, dev->base_addr); | ||
490 | |||
491 | /* Third nibble, hard-coded values */ | ||
492 | i = 0x26; | ||
493 | outb(i, dev->base_addr); | ||
494 | |||
495 | /* Fourth nibble sets shared ram page size */ | ||
496 | |||
497 | /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */ | ||
498 | i = (sramsize >> 4) & 0x07; | ||
499 | i = ((i == 4) ? 3 : i) << 2; | ||
500 | i |= 0x30; | ||
501 | |||
502 | if (ringspeed == 16) | ||
503 | i |= 2; | ||
504 | if (dev->base_addr == 0xA24) | ||
505 | i |= 1; | ||
506 | outb(i, dev->base_addr); | ||
507 | |||
508 | /* 0x40 will release the card for use */ | ||
509 | outb(0x40, dev->base_addr); | ||
510 | |||
511 | return; | ||
512 | } | ||
513 | |||
514 | static struct pcmcia_driver ibmtr_cs_driver = { | ||
515 | .owner = THIS_MODULE, | ||
516 | .drv = { | ||
517 | .name = "ibmtr_cs", | ||
518 | }, | ||
519 | .attach = ibmtr_attach, | ||
520 | .detach = ibmtr_detach, | ||
521 | }; | ||
522 | |||
523 | static int __init init_ibmtr_cs(void) | ||
524 | { | ||
525 | return pcmcia_register_driver(&ibmtr_cs_driver); | ||
526 | } | ||
527 | |||
528 | static void __exit exit_ibmtr_cs(void) | ||
529 | { | ||
530 | pcmcia_unregister_driver(&ibmtr_cs_driver); | ||
531 | BUG_ON(dev_list != NULL); | ||
532 | } | ||
533 | |||
534 | module_init(init_ibmtr_cs); | ||
535 | module_exit(exit_ibmtr_cs); | ||