Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_cs.c

Go to the documentation of this file.
00001 #define PRISM2_PCCARD
00002 
00003 #include <linux/config.h>
00004 #ifdef  __IN_PCMCIA_PACKAGE__
00005 #include <pcmcia/k_compat.h>
00006 #endif /* __IN_PCMCIA_PACKAGE__ */
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 /* __IN_PCMCIA_PACKAGE__ */
00037 
00038 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
00039 /* This behavior changed in some Linux 2.5.x version. I don't remember when and
00040  * don't really care if this does not work with some early 2.5.x versions..
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 /* PRISM2_IO_DEBUG */
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 /* PRISM2_IO_DEBUG */
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 /* FIX: This might change at some point.. */
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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         /* Setup Genesis mode */
00305         reg.Action = CS_WRITE;
00306         reg.Value = hcr;
00307         reg.Offset = CISREG_CCSR;
00308         res = pcmcia_access_configuration_register(local->link->handle, &reg);
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, &reg);
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 /* HOSTAP_USE_RELEASE_TIMER */
00354                 prism2_release((u_long) local->link);
00355 #endif /* HOSTAP_USE_RELEASE_TIMER */
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 /* allocate local data and register with CardServices
00382  * initialize dev_link structure, but do not configure the card yet */
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 /* HOSTAP_USE_RELEASE_TIMER */
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         /* register with CardServices */
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 /* HOSTAP_USE_RELEASE_TIMER */
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         /* release net devices */
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 /* run after a CARD_INSERTATION event is received to configure the PCMCIA
00508  * socket and make the device available to the system */
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         /* Look for an appropriate configuration table entry in the CIS */
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                 /* Does this card need audio output? */
00560                 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
00561                         link->conf.Attributes |= CONF_ENABLE_SPKR;
00562                         link->conf.Status = CCSR_AUDIO_ENA;
00563                 }
00564         
00565                 /* Use power settings for Vcc and Vpp if present */
00566                 /*  Note that the CIS values need to be rescaled */
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                 /* Do we need to allocate an interrupt? */
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                         /* At least Compaq WL200 does not have IRQInfo1 set,
00595                          * but it does not work without interrupts.. */
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                 /* IO window settings */
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                 /* This reserves IO space but doesn't actually enable it */
00628                 CFG_CHECK2(RequestIO,
00629                            pcmcia_request_io(link->handle, &link->io));
00630 
00631                 /* This configuration table entry is OK */
00632                 break;
00633 
00634         next_entry:
00635                 CS_CHECK(GetNextTuple,
00636                          pcmcia_get_next_tuple(link->handle, &tuple));
00637         }
00638 
00639         /*
00640          * Allocate an interrupt line.  Note that this does not assign a
00641          * handler to the interrupt, unless the 'Handler' member of the
00642          * irq structure is initialized.
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          * This actually configures the PCMCIA socket -- setting up
00661          * the I/O windows and the interrupt mapping, and putting the
00662          * card and host interface into "Memory and IO" mode.
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         /* Finally, report what we've done */
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 /* HOSTAP_USE_RELEASE_TIMER */
00768                         prism2_release((u_long) link);
00769 #endif /* HOSTAP_USE_RELEASE_TIMER */
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                 /* fall through */
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                 /* fall through */
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 /* HOSTAP_USE_RELEASE_TIMER */
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 /* LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) */
00874 
00875 
00876 module_init(init_prism2_pccard);
00877 module_exit(exit_prism2_pccard);

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1