00001 #define PRISM2_PCCARD
00002
00003 #include <linux/config.h>
00004 #ifdef __IN_PCMCIA_PACKAGE__
00005 #include <pcmcia/k_compat.h>
00006 #endif
00007 #include <linux/version.h>
00008 #include <linux/module.h>
00009 #include <linux/init.h>
00010 #include <linux/if.h>
00011 #include <linux/wait.h>
00012 #include <linux/timer.h>
00013 #include <linux/skbuff.h>
00014 #include <linux/netdevice.h>
00015 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44))
00016 #include <linux/tqueue.h>
00017 #else
00018 #include <linux/workqueue.h>
00019 #endif
00020 #include "hostap_wext.h"
00021
00022 #include <pcmcia/version.h>
00023 #include <pcmcia/cs_types.h>
00024 #include <pcmcia/cs.h>
00025 #include <pcmcia/cistpl.h>
00026 #include <pcmcia/cisreg.h>
00027 #include <pcmcia/ds.h>
00028
00029 #include <asm/io.h>
00030
00031 #include "hostap_wlan.h"
00032
00033
00034 #ifdef __IN_PCMCIA_PACKAGE__
00035 #include <pcmcia/config.h>
00036 #endif
00037
00038 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
00039
00040
00041
00042 #define HOSTAP_USE_RELEASE_TIMER
00043 #endif
00044
00045
00046 static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
00047 static dev_info_t dev_info = "hostap_cs";
00048 static dev_link_t *dev_list = NULL;
00049
00050 MODULE_AUTHOR("SSH Communications Security Corp, Jouni Malinen");
00051 MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
00052 "cards (PC Card).");
00053 MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
00054 MODULE_LICENSE("GPL");
00055
00056
00057 static unsigned int irq_mask = 0xdeb8;
00058 MODULE_PARM(irq_mask, "i");
00059
00060 static int irq_list[4] = { -1 };
00061 MODULE_PARM(irq_list, "1-4i");
00062
00063 static int ignore_cis_vcc = 0;
00064 MODULE_PARM(ignore_cis_vcc, "i");
00065 MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
00066
00067
00068 #ifdef PRISM2_IO_DEBUG
00069
00070 static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
00071 {
00072 struct hostap_interface *iface = dev->priv;
00073 local_info_t *local = iface->local;
00074 unsigned long flags;
00075
00076 spin_lock_irqsave(&local->lock, flags);
00077 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
00078 outb(v, dev->base_addr + a);
00079 spin_unlock_irqrestore(&local->lock, flags);
00080 }
00081
00082 static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
00083 {
00084 struct hostap_interface *iface = dev->priv;
00085 local_info_t *local = iface->local;
00086 unsigned long flags;
00087 u8 v;
00088
00089 spin_lock_irqsave(&local->lock, flags);
00090 v = inb(dev->base_addr + a);
00091 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
00092 spin_unlock_irqrestore(&local->lock, flags);
00093 return v;
00094 }
00095
00096 static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
00097 {
00098 struct hostap_interface *iface = dev->priv;
00099 local_info_t *local = iface->local;
00100 unsigned long flags;
00101
00102 spin_lock_irqsave(&local->lock, flags);
00103 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
00104 outw(v, dev->base_addr + a);
00105 spin_unlock_irqrestore(&local->lock, flags);
00106 }
00107
00108 static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
00109 {
00110 struct hostap_interface *iface = dev->priv;
00111 local_info_t *local = iface->local;
00112 unsigned long flags;
00113 u16 v;
00114
00115 spin_lock_irqsave(&local->lock, flags);
00116 v = inw(dev->base_addr + a);
00117 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
00118 spin_unlock_irqrestore(&local->lock, flags);
00119 return v;
00120 }
00121
00122 static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
00123 u8 *buf, int wc)
00124 {
00125 struct hostap_interface *iface = dev->priv;
00126 local_info_t *local = iface->local;
00127 unsigned long flags;
00128
00129 spin_lock_irqsave(&local->lock, flags);
00130 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
00131 outsw(dev->base_addr + a, buf, wc);
00132 spin_unlock_irqrestore(&local->lock, flags);
00133 }
00134
00135 static inline void hfa384x_insw_debug(struct net_device *dev, int a,
00136 u8 *buf, int wc)
00137 {
00138 struct hostap_interface *iface = dev->priv;
00139 local_info_t *local = iface->local;
00140 unsigned long flags;
00141
00142 spin_lock_irqsave(&local->lock, flags);
00143 prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
00144 insw(dev->base_addr + a, buf, wc);
00145 spin_unlock_irqrestore(&local->lock, flags);
00146 }
00147
00148 #define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
00149 #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
00150 #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
00151 #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
00152 #define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
00153 #define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
00154
00155 #else
00156
00157 #define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
00158 #define HFA384X_INB(a) inb(dev->base_addr + (a))
00159 #define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
00160 #define HFA384X_INW(a) inw(dev->base_addr + (a))
00161 #define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
00162 #define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
00163
00164 #endif
00165
00166
00167 static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
00168 int len)
00169 {
00170 u16 d_off;
00171 u16 *pos;
00172
00173 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00174 pos = (u16 *) buf;
00175
00176 if (len / 2)
00177 HFA384X_INSW(d_off, buf, len / 2);
00178 pos += len / 2;
00179
00180 if (len & 1)
00181 *((char *) pos) = HFA384X_INB(d_off);
00182
00183 return 0;
00184 }
00185
00186
00187 static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
00188 {
00189 u16 d_off;
00190 u16 *pos;
00191
00192 d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
00193 pos = (u16 *) buf;
00194
00195 if (len / 2)
00196 HFA384X_OUTSW(d_off, buf, len / 2);
00197 pos += len / 2;
00198
00199 if (len & 1)
00200 HFA384X_OUTB(*((char *) pos), d_off);
00201
00202 return 0;
00203 }
00204
00205
00206
00207 #include "hostap_hw.c"
00208
00209
00210
00211 static void prism2_detach(dev_link_t *link);
00212 static void prism2_release(u_long arg);
00213 static int prism2_event(event_t event, int priority,
00214 event_callback_args_t *args);
00215
00216
00217 static int prism2_pccard_card_present(local_info_t *local)
00218 {
00219 if (local->link != NULL &&
00220 ((local->link->state & (DEV_PRESENT | DEV_CONFIG)) ==
00221 (DEV_PRESENT | DEV_CONFIG)))
00222 return 1;
00223 return 0;
00224 }
00225
00226 static void prism2_pccard_cor_sreset(local_info_t *local)
00227 {
00228 int res;
00229 conf_reg_t reg;
00230
00231 if (!prism2_pccard_card_present(local))
00232 return;
00233
00234 reg.Function = 0;
00235 reg.Action = CS_READ;
00236 reg.Offset = CISREG_COR;
00237 reg.Value = 0;
00238 res = pcmcia_access_configuration_register(local->link->handle, ®);
00239 if (res != CS_SUCCESS) {
00240 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
00241 res);
00242 return;
00243 }
00244 printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
00245 reg.Value);
00246
00247 reg.Action = CS_WRITE;
00248 reg.Value |= COR_SOFT_RESET;
00249 res = pcmcia_access_configuration_register(local->link->handle, ®);
00250 if (res != CS_SUCCESS) {
00251 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
00252 res);
00253 return;
00254 }
00255
00256 mdelay(1);
00257
00258 reg.Value &= ~COR_SOFT_RESET;
00259 res = pcmcia_access_configuration_register(local->link->handle, ®);
00260 if (res != CS_SUCCESS) {
00261 printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
00262 res);
00263 return;
00264 }
00265
00266 mdelay(1);
00267 }
00268
00269
00270 static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
00271 {
00272 int res;
00273 conf_reg_t reg;
00274 int old_cor;
00275
00276 if (!prism2_pccard_card_present(local))
00277 return;
00278
00279 reg.Function = 0;
00280 reg.Action = CS_READ;
00281 reg.Offset = CISREG_COR;
00282 reg.Value = 0;
00283 res = pcmcia_access_configuration_register(local->link->handle, ®);
00284 if (res != CS_SUCCESS) {
00285 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 "
00286 "(%d)\n", res);
00287 return;
00288 }
00289 printk(KERN_DEBUG "prism2_pccard_genesis_sreset: original COR %02x\n",
00290 reg.Value);
00291 old_cor = reg.Value;
00292
00293 reg.Action = CS_WRITE;
00294 reg.Value |= COR_SOFT_RESET;
00295 res = pcmcia_access_configuration_register(local->link->handle, ®);
00296 if (res != CS_SUCCESS) {
00297 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 "
00298 "(%d)\n", res);
00299 return;
00300 }
00301
00302 mdelay(10);
00303
00304
00305 reg.Action = CS_WRITE;
00306 reg.Value = hcr;
00307 reg.Offset = CISREG_CCSR;
00308 res = pcmcia_access_configuration_register(local->link->handle, ®);
00309 if (res != CS_SUCCESS) {
00310 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 "
00311 "(%d)\n", res);
00312 return;
00313 }
00314 mdelay(10);
00315
00316 reg.Action = CS_WRITE;
00317 reg.Offset = CISREG_COR;
00318 reg.Value = old_cor & ~COR_SOFT_RESET;
00319 res = pcmcia_access_configuration_register(local->link->handle, ®);
00320 if (res != CS_SUCCESS) {
00321 printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 "
00322 "(%d)\n", res);
00323 return;
00324 }
00325
00326 mdelay(10);
00327 }
00328
00329
00330 static int prism2_pccard_dev_open(local_info_t *local)
00331 {
00332 local->link->open++;
00333 return 0;
00334 }
00335
00336
00337 static int prism2_pccard_dev_close(local_info_t *local)
00338 {
00339 if (local == NULL || local->link == NULL)
00340 return 1;
00341
00342 if (!local->link->open) {
00343 printk(KERN_WARNING "%s: prism2_pccard_dev_close(): "
00344 "link not open?!\n", local->dev->name);
00345 return 1;
00346 }
00347
00348 local->link->open--;
00349
00350 if (local->link->state & DEV_STALE_CONFIG) {
00351 #ifdef HOSTAP_USE_RELEASE_TIMER
00352 mod_timer(&local->link->release, jiffies + HZ / 20);
00353 #else
00354 prism2_release((u_long) local->link);
00355 #endif
00356 }
00357
00358 return 0;
00359 }
00360
00361
00362 static struct prism2_helper_functions prism2_pccard_funcs =
00363 {
00364 .card_present = prism2_pccard_card_present,
00365 .cor_sreset = prism2_pccard_cor_sreset,
00366 .dev_open = prism2_pccard_dev_open,
00367 .dev_close = prism2_pccard_dev_close,
00368 .genesis_reset = prism2_pccard_genesis_reset,
00369 };
00370
00371
00372 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,68)
00373 static void cs_error(client_handle_t handle, int func, int ret)
00374 {
00375 error_info_t err = { func, ret };
00376 pcmcia_report_error(handle, &err);
00377 }
00378 #endif
00379
00380
00381
00382
00383 static dev_link_t *prism2_attach(void)
00384 {
00385 dev_link_t *link;
00386 local_info_t *local;
00387 client_reg_t client_reg;
00388 int ret;
00389 struct net_device *dev;
00390 struct hostap_interface *iface;
00391
00392 for (link = dev_list; link; link = link->next) {
00393 if (link->state & DEV_STALE_LINK) {
00394 printk("%s: flushing stale link\n", dev_info);
00395 prism2_detach(link);
00396 }
00397 }
00398
00399 link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
00400 if (link == NULL)
00401 return NULL;
00402
00403 memset(link, 0, sizeof(dev_link_t));
00404
00405 dev = prism2_init_local_data(&prism2_pccard_funcs, 0);
00406 if (dev == NULL) {
00407 kfree(link);
00408 return NULL;
00409 }
00410 iface = dev->priv;
00411 local = iface->local;
00412
00413 link->priv = dev;
00414 local->link = link;
00415
00416 #ifdef HOSTAP_USE_RELEASE_TIMER
00417 init_timer(&link->release);
00418 link->release.function = &prism2_release;
00419 link->release.data = (u_long)link;
00420 #endif
00421
00422 PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
00423 link->conf.Vcc = 33;
00424 link->conf.IntType = INT_MEMORY_AND_IO;
00425
00426
00427 link->next = dev_list;
00428 dev_list = link;
00429 client_reg.dev_info = &dev_info;
00430 client_reg.Attributes = INFO_IO_CLIENT;
00431 client_reg.EventMask = CS_EVENT_CARD_INSERTION |
00432 CS_EVENT_CARD_REMOVAL |
00433 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
00434 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
00435 client_reg.event_handler = &prism2_event;
00436 client_reg.Version = 0x0210;
00437 client_reg.event_callback_args.client_data = link;
00438 ret = pcmcia_register_client(&link->handle, &client_reg);
00439 if (ret != CS_SUCCESS) {
00440 cs_error(link->handle, RegisterClient, ret);
00441 prism2_detach(link);
00442 return NULL;
00443 }
00444 return link;
00445 }
00446
00447
00448 static void prism2_detach(dev_link_t *link)
00449 {
00450 dev_link_t **linkp;
00451
00452 PDEBUG(DEBUG_FLOW, "prism2_detach\n");
00453
00454 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
00455 if (*linkp == link)
00456 break;
00457 if (*linkp == NULL) {
00458 printk(KERN_WARNING "%s: Attempt to detach non-existing "
00459 "PCMCIA client\n", dev_info);
00460 return;
00461 }
00462
00463 #ifdef HOSTAP_USE_RELEASE_TIMER
00464 del_timer(&link->release);
00465 #endif
00466 if (link->state & DEV_CONFIG) {
00467 printk("%s: detach postponed, '%s' still locked\n",
00468 dev_info, link->dev->dev_name);
00469 prism2_release((u_long)link);
00470 if (link->state & DEV_STALE_CONFIG) {
00471 link->state |= DEV_STALE_LINK;
00472 return;
00473 }
00474 }
00475
00476 if (link->handle) {
00477 int res = pcmcia_deregister_client(link->handle);
00478 if (res) {
00479 printk("CardService(DeregisterClient) => %d\n", res);
00480 cs_error(link->handle, DeregisterClient, res);
00481 }
00482 }
00483
00484 *linkp = link->next;
00485
00486 if (link->priv) {
00487 prism2_free_local_data((struct net_device *) link->priv);
00488
00489 }
00490 kfree(link);
00491 }
00492
00493
00494 #define CS_CHECK(fn, ret) \
00495 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
00496
00497 #define CFG_CHECK2(fn, retf) \
00498 do { int ret = (retf); \
00499 if (ret != 0) { \
00500 PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \
00501 cs_error(link->handle, fn, ret); \
00502 goto next_entry; \
00503 } \
00504 } while (0)
00505
00506
00507
00508
00509 static int prism2_config(dev_link_t *link)
00510 {
00511 struct net_device *dev = (struct net_device *) link->priv;
00512 struct hostap_interface *iface = dev->priv;
00513 local_info_t *local = iface->local;
00514 int ret;
00515 tuple_t tuple;
00516 cisparse_t parse;
00517 int last_fn, last_ret;
00518 u_char buf[64];
00519 config_info_t conf;
00520 cistpl_cftable_entry_t dflt = { 0 };
00521
00522 PDEBUG(DEBUG_FLOW, "prism2_config()\n");
00523
00524 tuple.DesiredTuple = CISTPL_CONFIG;
00525 tuple.Attributes = 0;
00526 tuple.TupleData = buf;
00527 tuple.TupleDataMax = sizeof(buf);
00528 tuple.TupleOffset = 0;
00529 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
00530 CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple));
00531 CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, &parse));
00532 link->conf.ConfigBase = parse.config.base;
00533 link->conf.Present = parse.config.rmask[0];
00534
00535 CS_CHECK(GetConfigurationInfo,
00536 pcmcia_get_configuration_info(link->handle, &conf));
00537 PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info,
00538 ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc);
00539 link->conf.Vcc = conf.Vcc;
00540
00541
00542 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
00543 CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple));
00544 for (;;) {
00545 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
00546 CFG_CHECK2(GetTupleData,
00547 pcmcia_get_tuple_data(link->handle, &tuple));
00548 CFG_CHECK2(ParseTuple,
00549 pcmcia_parse_tuple(link->handle, &tuple, &parse));
00550
00551 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
00552 dflt = *cfg;
00553 if (cfg->index == 0)
00554 goto next_entry;
00555 link->conf.ConfigIndex = cfg->index;
00556 PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
00557 "(default 0x%02X)\n", cfg->index, dflt.index);
00558
00559
00560 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
00561 link->conf.Attributes |= CONF_ENABLE_SPKR;
00562 link->conf.Status = CCSR_AUDIO_ENA;
00563 }
00564
00565
00566
00567 if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
00568 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
00569 10000 && !ignore_cis_vcc) {
00570 PDEBUG(DEBUG_EXTRA, " Vcc mismatch - skipping"
00571 " this entry\n");
00572 goto next_entry;
00573 }
00574 } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
00575 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
00576 10000 && !ignore_cis_vcc) {
00577 PDEBUG(DEBUG_EXTRA, " Vcc (default) mismatch "
00578 "- skipping this entry\n");
00579 goto next_entry;
00580 }
00581 }
00582
00583 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
00584 link->conf.Vpp1 = link->conf.Vpp2 =
00585 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
00586 else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
00587 link->conf.Vpp1 = link->conf.Vpp2 =
00588 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
00589
00590
00591 if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
00592 link->conf.Attributes |= CONF_ENABLE_IRQ;
00593 else if (!(link->conf.Attributes & CONF_ENABLE_IRQ)) {
00594
00595
00596 printk("Config has no IRQ info, but trying to enable "
00597 "IRQ anyway..\n");
00598 link->conf.Attributes |= CONF_ENABLE_IRQ;
00599 }
00600
00601
00602 PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
00603 "dflt.io.nwin=%d\n",
00604 cfg->io.nwin, dflt.io.nwin);
00605 link->io.NumPorts1 = link->io.NumPorts2 = 0;
00606 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
00607 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
00608 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
00609 PDEBUG(DEBUG_EXTRA, "io->flags = 0x%04X, "
00610 "io.base=0x%04x, len=%d\n", io->flags,
00611 io->win[0].base, io->win[0].len);
00612 if (!(io->flags & CISTPL_IO_8BIT))
00613 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
00614 if (!(io->flags & CISTPL_IO_16BIT))
00615 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
00616 link->io.IOAddrLines = io->flags &
00617 CISTPL_IO_LINES_MASK;
00618 link->io.BasePort1 = io->win[0].base;
00619 link->io.NumPorts1 = io->win[0].len;
00620 if (io->nwin > 1) {
00621 link->io.Attributes2 = link->io.Attributes1;
00622 link->io.BasePort2 = io->win[1].base;
00623 link->io.NumPorts2 = io->win[1].len;
00624 }
00625 }
00626
00627
00628 CFG_CHECK2(RequestIO,
00629 pcmcia_request_io(link->handle, &link->io));
00630
00631
00632 break;
00633
00634 next_entry:
00635 CS_CHECK(GetNextTuple,
00636 pcmcia_get_next_tuple(link->handle, &tuple));
00637 }
00638
00639
00640
00641
00642
00643
00644 if (link->conf.Attributes & CONF_ENABLE_IRQ) {
00645 int i;
00646 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
00647 link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
00648 if (irq_list[0] == -1)
00649 link->irq.IRQInfo2 = irq_mask;
00650 else
00651 for (i = 0; i < 4; i++)
00652 link->irq.IRQInfo2 |= 1 << irq_list[i];
00653 link->irq.Handler = (void *) prism2_interrupt;
00654 link->irq.Instance = dev;
00655 CS_CHECK(RequestIRQ,
00656 pcmcia_request_irq(link->handle, &link->irq));
00657 }
00658
00659
00660
00661
00662
00663
00664 CS_CHECK(RequestConfiguration,
00665 pcmcia_request_configuration(link->handle, &link->conf));
00666
00667 dev->irq = link->irq.AssignedIRQ;
00668 dev->base_addr = link->io.BasePort1;
00669
00670
00671 printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
00672 dev_info, link->conf.ConfigIndex,
00673 link->conf.Vcc / 10, link->conf.Vcc % 10);
00674 if (link->conf.Vpp1)
00675 printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
00676 link->conf.Vpp1 % 10);
00677 if (link->conf.Attributes & CONF_ENABLE_IRQ)
00678 printk(", irq %d", link->irq.AssignedIRQ);
00679 if (link->io.NumPorts1)
00680 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
00681 link->io.BasePort1+link->io.NumPorts1-1);
00682 if (link->io.NumPorts2)
00683 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
00684 link->io.BasePort2+link->io.NumPorts2-1);
00685 printk("\n");
00686
00687 link->state |= DEV_CONFIG;
00688 link->state &= ~DEV_CONFIG_PENDING;
00689
00690 if (prism2_init_dev(local)) {
00691 prism2_release((u_long) link);
00692 return 1;
00693 }
00694
00695 strcpy(local->node.dev_name, dev->name);
00696 link->dev = &local->node;
00697
00698 local->shutdown = 0;
00699
00700 ret = prism2_hw_config(dev, 1);
00701 return ret;
00702
00703 cs_failed:
00704 cs_error(link->handle, last_fn, last_ret);
00705 prism2_release((u_long)link);
00706 return 1;
00707 }
00708
00709
00710 static void prism2_release(u_long arg)
00711 {
00712 dev_link_t *link = (dev_link_t *)arg;
00713 struct net_device *dev = (struct net_device *) link->priv;
00714 struct hostap_interface *iface = dev->priv;
00715 local_info_t *local = iface->local;
00716
00717 PDEBUG(DEBUG_FLOW, "prism2_release\n");
00718
00719 if (link->open) {
00720 printk("%s: release postponed, '%s' still open\n",
00721 dev_info, link->dev->dev_name);
00722 link->state |= DEV_STALE_CONFIG;
00723 return;
00724 }
00725
00726 if (dev != NULL)
00727 prism2_hw_shutdown(dev, 0);
00728
00729 local->shutdown = 1;
00730
00731 if (link->win)
00732 pcmcia_release_window(link->win);
00733 pcmcia_release_configuration(link->handle);
00734 if (link->io.NumPorts1)
00735 pcmcia_release_io(link->handle, &link->io);
00736 if (link->irq.AssignedIRQ)
00737 pcmcia_release_irq(link->handle, &link->irq);
00738
00739 link->state &= ~DEV_CONFIG;
00740
00741 PDEBUG(DEBUG_FLOW, "release - done\n");
00742 }
00743
00744
00745 static int prism2_event(event_t event, int priority,
00746 event_callback_args_t *args)
00747 {
00748 dev_link_t *link = args->client_data;
00749 struct net_device *dev = (struct net_device *) link->priv;
00750
00751 switch (event) {
00752 case CS_EVENT_CARD_INSERTION:
00753 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info);
00754 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
00755 if (prism2_config(link))
00756 dev->irq = 0;
00757 break;
00758
00759 case CS_EVENT_CARD_REMOVAL:
00760 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info);
00761 link->state &= ~DEV_PRESENT;
00762 if (link->state & DEV_CONFIG) {
00763 hostap_netif_stop_queues(dev);
00764 netif_device_detach(dev);
00765 #ifdef HOSTAP_USE_RELEASE_TIMER
00766 mod_timer(&link->release, jiffies + HZ / 20);
00767 #else
00768 prism2_release((u_long) link);
00769 #endif
00770 }
00771 break;
00772
00773 case CS_EVENT_PM_SUSPEND:
00774 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
00775 link->state |= DEV_SUSPEND;
00776
00777
00778 case CS_EVENT_RESET_PHYSICAL:
00779 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info);
00780 if (link->state & DEV_CONFIG) {
00781 if (link->open) {
00782 hostap_netif_stop_queues(dev);
00783 netif_device_detach(dev);
00784 }
00785 pcmcia_release_configuration(link->handle);
00786 }
00787 break;
00788
00789 case CS_EVENT_PM_RESUME:
00790 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
00791 link->state &= ~DEV_SUSPEND;
00792
00793
00794 case CS_EVENT_CARD_RESET:
00795 PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info);
00796 if (link->state & DEV_CONFIG) {
00797 pcmcia_request_configuration(link->handle,
00798 &link->conf);
00799 prism2_hw_shutdown(dev, 1);
00800 prism2_hw_config(dev, link->open ? 0 : 1);
00801 if (link->open) {
00802 netif_device_attach(dev);
00803 netif_start_queue(dev);
00804 }
00805 }
00806 break;
00807
00808 default:
00809 PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n",
00810 dev_info, event);
00811 break;
00812 }
00813 return 0;
00814 }
00815
00816
00817 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67)
00818 static struct pcmcia_driver hostap_driver = {
00819 .drv = {
00820 .name = "hostap_cs",
00821 },
00822 .attach = prism2_attach,
00823 .detach = prism2_detach,
00824 .owner = THIS_MODULE,
00825 };
00826
00827 static int __init init_prism2_pccard(void)
00828 {
00829 printk(KERN_INFO "%s: %s\n", dev_info, version);
00830 return pcmcia_register_driver(&hostap_driver);
00831 }
00832
00833 static void __exit exit_prism2_pccard(void)
00834 {
00835 pcmcia_unregister_driver(&hostap_driver);
00836 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
00837 }
00838
00839 #else
00840
00841 static int __init init_prism2_pccard(void)
00842 {
00843 servinfo_t serv;
00844
00845 printk(KERN_INFO "%s: %s\n", dev_info, version);
00846 pcmcia_get_card_services_info(&serv);
00847 if (serv.Revision != CS_RELEASE_CODE) {
00848 printk(KERN_NOTICE
00849 "%s: CardServices release does not match!\n", dev_info);
00850 return -1;
00851 }
00852 register_pccard_driver(&dev_info, &prism2_attach, &prism2_detach);
00853
00854 return 0;
00855 }
00856
00857
00858 static void __exit exit_prism2_pccard(void)
00859 {
00860 unregister_pccard_driver(&dev_info);
00861 while (dev_list) {
00862 PDEBUG(DEBUG_FLOW, "exit_prism2 - detaching device\n");
00863 #ifdef HOSTAP_USE_RELEASE_TIMER
00864 del_timer(&dev_list->release);
00865 #endif
00866 if (dev_list->state & DEV_CONFIG)
00867 prism2_release((u_long)dev_list);
00868 prism2_detach(dev_list);
00869 }
00870
00871 printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
00872 }
00873 #endif
00874
00875
00876 module_init(init_prism2_pccard);
00877 module_exit(exit_prism2_pccard);