/*---------------------------------------------------------------- * prism2sta_release * * Half of the config/release pair. Usually called in response to * a card ejection event. Checks to make sure no higher layers * are still (or think they are) using the card via the link->open * field. * * NOTE: Don't forget to increment the link->open variable in the * device_open method, and decrement it in the device_close * method. * * Arguments: * arg a generic 32 bit variable. It's the value that * we assigned to link->release.data in sta_attach(). * * Returns: * nothing * * Side effects: * All resources should be released after this function * executes and finds the device !open. * * Call context: * Possibly in a timer context. Don't do anything that'll * block. ----------------------------------------------------------------*/ void prism2sta_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; DBFENTER; /* First thing we should do is get the MSD back to the * HWPRESENT state. I.e. everything quiescent. */ prism2sta_ifstate(link->priv, P80211ENUM_ifstate_disable); if (link->open) { /* TODO: I don't think we're even using this bit of code * and I don't think it's hurting us at the moment. */ WLAN_LOG_DEBUG(1, "prism2sta_cs: release postponed, '%s' still open\n", link->dev->dev_name); link->state |= DEV_STALE_CONFIG; return; } pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); DBFEXIT; }
/*---------------------------------------------------------------- * p80211indicate_init * * Called during the p80211 startup to set up the netlink interfaces * for sniffing and indication messages. * * Arguments: * none * * Returns: * nothing * * Call context: * Any ----------------------------------------------------------------*/ void p80211indicate_init(void) { DBFENTER; nl_indicate = netlink_kernel_create( P80211_NL_SOCK_IND, &p80211ind_rx); if ( nl_indicate == NULL ) { WLAN_LOG_DEBUG(2,"Failed to create indicate netlink i/f.\n"); } DBFEXIT; return; }
/*---------------------------------------------------------------- * p80211knetdev_do_ioctl * * Handle an ioctl call on one of our devices. Everything Linux * ioctl specific is done here. Then we pass the contents of the * ifr->data to the request message handler. * * Arguments: * dev Linux kernel netdevice * ifr Our private ioctl request structure, typed for the * generic struct ifreq so we can use ptr to func * w/o cast. * * Returns: * zero on success, a negative errno on failure. Possible values: * -ENETDOWN Device isn't up. * -EBUSY cmd already in progress * -ETIME p80211 cmd timed out (MSD may have its own timers) * -EFAULT memory fault copying msg from user buffer * -ENOMEM unable to allocate kernel msg buffer * -ENOSYS bad magic, it the cmd really for us? * -EintR sleeping on cmd, awakened by signal, cmd cancelled. * * Call Context: * Process thread (ioctl caller). TODO: SMP support may require * locks. ----------------------------------------------------------------*/ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { int result = 0; p80211ioctl_req_t *req = (p80211ioctl_req_t*)ifr; wlandevice_t *wlandev = dev->ml_priv; u8 *msgbuf; DBFENTER; WLAN_LOG_DEBUG(2, "rx'd ioctl, cmd=%d, len=%d\n", cmd, req->len); #ifdef SIOCETHTOOL if (cmd == SIOCETHTOOL) { result = p80211netdev_ethtool(wlandev, (void __user *) ifr->ifr_data); goto bail; } #endif /* Test the magic, assume ifr is good if it's there */ if ( req->magic != P80211_IOCTL_MAGIC ) { result = -ENOSYS; goto bail; } if ( cmd == P80211_IFTEST ) { result = 0; goto bail; } else if ( cmd != P80211_IFREQ ) { result = -ENOSYS; goto bail; } /* Allocate a buf of size req->len */ if ((msgbuf = kmalloc( req->len, GFP_KERNEL))) { if ( copy_from_user( msgbuf, (void __user *) req->data, req->len) ) { result = -EFAULT; } else { result = p80211req_dorequest( wlandev, msgbuf); } if ( result == 0 ) { if ( copy_to_user( (void __user *) req->data, msgbuf, req->len)) { result = -EFAULT; } } kfree(msgbuf); } else { result = -ENOMEM; } bail: DBFEXIT; return result; /* If allocate,copyfrom or copyto fails, return errno */ }
/*---------------------------------------------------------------- * p80211ind_mlme * * Called by the MSD to deliver an mlme type indication message. * * Arguments: * wlandev WLAN device struct * skb skb containing message to deliver * * Returns: * nothing * * Call context: * Any ----------------------------------------------------------------*/ void p80211ind_mlme( wlandevice_t *wlandev, struct sk_buff *skb) { DBFENTER; if ( nl_indicate != NULL ) { /* TODO: Look at queuing mlme indications when requests are pending. */ netlink_broadcast(nl_indicate, skb, 0, P80211_NL_MCAST_GRP_MLME, GFP_ATOMIC); } else { WLAN_LOG_DEBUG(2,"Can't send indicate msg, no netlink i/f\n"); } DBFEXIT; return; }
/*---------------------------------------------------------------- * p80211ind_distribution * * Called by the MSD to deliver a distribution system type * indication message. * * Arguments: * wlandev WLAN device struct * skb skb containing message to deliver * * Returns: * nothing * * Call context: * Any ----------------------------------------------------------------*/ void p80211ind_distribution( wlandevice_t *wlandev, struct sk_buff *skb) { DBFENTER; if ( nl_indicate != NULL ) { /* skb = alloc_skb(len, GFP_ATOMIC); skb_put(skb, len); memcpy(skb->data, msg, len); */ netlink_broadcast(nl_indicate, skb, 0, P80211_NL_MCAST_GRP_DIST, GFP_ATOMIC); } else { WLAN_LOG_DEBUG(2,"Can't send indicate msg, no netlink i/f\n"); } DBFEXIT; return; }
int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) { int result = 0; #define COR_OFFSET 0x3e0 /* COR attribute offset of Prism2 PC card */ #define COR_VALUE 0x41 /* Enable PC card with irq in level trigger */ #define HCR_OFFSET 0x3e2 /* HCR attribute offset of Prism2 PC card */ UINT8 corsave; DBFENTER; WLAN_LOG_DEBUG(3, "Doing reset via direct COR access.\n"); /* Collect COR */ corsave = readb(hw->membase + COR_OFFSET); /* Write reset bit (BIT7) */ writeb(corsave | BIT7, hw->membase + COR_OFFSET); /* Hold for holdtime */ mdelay(holdtime); if (genesis) { writeb(genesis, hw->membase + HCR_OFFSET); /* Hold for holdtime */ mdelay(holdtime); } /* Clear reset bit */ writeb(corsave & ~BIT7, hw->membase + COR_OFFSET); /* Wait for settletime */ mdelay(settletime); /* Set non-reset bits back what they were */ writeb(corsave, hw->membase + COR_OFFSET); DBFEXIT; return result; }
/*---------------------------------------------------------------- * p80211knetdev_hard_start_xmit * * Linux netdevice method for transmitting a frame. * * Arguments: * skb Linux sk_buff containing the frame. * netdev Linux netdevice. * * Side effects: * If the lower layers report that buffers are full. netdev->tbusy * will be set to prevent higher layers from sending more traffic. * * Note: If this function returns non-zero, higher layers retain * ownership of the skb. * * Returns: * zero on success, non-zero on failure. ----------------------------------------------------------------*/ static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netdev) { int result = 0; int txresult = -1; wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; p80211_hdr_t p80211_hdr; p80211_metawep_t p80211_wep; DBFENTER; if (skb == NULL) { return 0; } if (wlandev->state != WLAN_DEVICE_OPEN) { result = 1; goto failed; } memset(&p80211_hdr, 0, sizeof(p80211_hdr_t)); memset(&p80211_wep, 0, sizeof(p80211_metawep_t)); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,38) ) if ( test_and_set_bit(0, (void*)&(netdev->tbusy)) != 0 ) { /* We've been called w/ tbusy set, has the tx */ /* path stalled? */ WLAN_LOG_DEBUG(1, "called when tbusy set\n"); result = 1; goto failed; } #else if ( netif_queue_stopped(netdev) ) { WLAN_LOG_DEBUG(1, "called when queue stopped.\n"); result = 1; goto failed; } netif_stop_queue(netdev); /* No timeout handling here, 2.3.38+ kernels call the * timeout function directly. * TODO: Add timeout handling. */ #endif /* Check to see that a valid mode is set */ switch( wlandev->macmode ) { case WLAN_MACMODE_IBSS_STA: case WLAN_MACMODE_ESS_STA: case WLAN_MACMODE_ESS_AP: break; default: /* Mode isn't set yet, just drop the frame * and return success . * TODO: we need a saner way to handle this */ if(skb->protocol != ETH_P_80211_RAW) { p80211netdev_start_queue(wlandev); WLAN_LOG_NOTICE( "Tx attempt prior to association, frame dropped.\n"); wlandev->linux_stats.tx_dropped++; result = 0; goto failed; } break; } /* Check for raw transmits */ if(skb->protocol == ETH_P_80211_RAW) { if (!capable(CAP_NET_ADMIN)) { result = 1; goto failed; } /* move the header over */ memcpy(&p80211_hdr, skb->data, sizeof(p80211_hdr_t)); skb_pull(skb, sizeof(p80211_hdr_t)); } else { if ( skb_ether_to_p80211(wlandev, wlandev->ethconv, skb, &p80211_hdr, &p80211_wep) != 0 ) { /* convert failed */ WLAN_LOG_DEBUG(1, "ether_to_80211(%d) failed.\n", wlandev->ethconv); result = 1; goto failed; } } if ( wlandev->txframe == NULL ) { result = 1; goto failed; } netdev->trans_start = jiffies; wlandev->linux_stats.tx_packets++; /* count only the packet payload */ wlandev->linux_stats.tx_bytes += skb->len; txresult = wlandev->txframe(wlandev, skb, &p80211_hdr, &p80211_wep); if ( txresult == 0) { /* success and more buf */ /* avail, re: hw_txdata */ p80211netdev_wake_queue(wlandev); result = 0; } else if ( txresult == 1 ) { /* success, no more avail */ WLAN_LOG_DEBUG(3, "txframe success, no more bufs\n"); /* netdev->tbusy = 1; don't set here, irqhdlr */ /* may have already cleared it */ result = 0; } else if ( txresult == 2 ) { /* alloc failure, drop frame */ WLAN_LOG_DEBUG(3, "txframe returned alloc_fail\n"); result = 1; } else { /* buffer full or queue busy, drop frame. */ WLAN_LOG_DEBUG(3, "txframe returned full or busy\n"); result = 1; } failed: /* Free up the WEP buffer if it's not the same as the skb */ if ((p80211_wep.data) && (p80211_wep.data != skb->data)) kfree(p80211_wep.data); /* we always free the skb here, never in a lower level. */ if (!result) dev_kfree_skb(skb); DBFEXIT; return result; }
/*---------------------------------------------------------------- * p80211netdev_rx_bh * * Deferred processing of all received frames. * * Arguments: * wlandev WLAN network device structure * skb skbuff containing a full 802.11 frame. * Returns: * nothing * Side effects: * ----------------------------------------------------------------*/ static void p80211netdev_rx_bh(unsigned long arg) { wlandevice_t *wlandev = (wlandevice_t *) arg; struct sk_buff *skb = NULL; netdevice_t *dev = wlandev->netdev; p80211_hdr_a3_t *hdr; UINT16 fc; DBFENTER; /* Let's empty our our queue */ while ( (skb = skb_dequeue(&wlandev->nsd_rxq)) ) { if (wlandev->state == WLAN_DEVICE_OPEN) { if (dev->type != ARPHRD_ETHER) { /* RAW frame; we shouldn't convert it */ // XXX Append the Prism Header here instead. /* set up various data fields */ skb->dev = dev; skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_NONE; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_80211_RAW); dev->last_rx = jiffies; wlandev->linux_stats.rx_packets++; wlandev->linux_stats.rx_bytes += skb->len; netif_rx_ni(skb); continue; } else { hdr = (p80211_hdr_a3_t *)skb->data; fc = ieee2host16(hdr->fc); if (p80211_rx_typedrop(wlandev, fc)) { dev_kfree_skb(skb); continue; } /* perform mcast filtering */ if (wlandev->netdev->flags & IFF_ALLMULTI) { /* allow my local address through */ if (memcmp(hdr->a1, wlandev->netdev->dev_addr, WLAN_ADDR_LEN) != 0) { /* but reject anything else that isn't multicast */ if (!(hdr->a1[0] & 0x01)) { dev_kfree_skb(skb); continue; } } } if ( skb_p80211_to_ether(wlandev, wlandev->ethconv, skb) == 0 ) { skb->dev->last_rx = jiffies; wlandev->linux_stats.rx_packets++; wlandev->linux_stats.rx_bytes += skb->len; netif_rx_ni(skb); continue; } WLAN_LOG_DEBUG(1, "p80211_to_ether failed.\n"); } } dev_kfree_skb(skb); } DBFEXIT; }
/*---------------------------------------------------------------- * p80211_rx_typedrop * * Classifies the frame, increments the appropriate counter, and * returns 0|1|2 indicating whether the driver should handle, ignore, or * drop the frame * * Arguments: * wlandev wlan device structure * fc frame control field * * Returns: * zero if the frame should be handled by the driver, * one if the frame should be ignored * anything else means we drop it. * * Side effects: * * Call context: * interrupt ----------------------------------------------------------------*/ static int p80211_rx_typedrop( wlandevice_t *wlandev, UINT16 fc) { UINT16 ftype; UINT16 fstype; int drop = 0; /* Classify frame, increment counter */ ftype = WLAN_GET_FC_FTYPE(fc); fstype = WLAN_GET_FC_FSTYPE(fc); #if 0 WLAN_LOG_DEBUG(4, "rx_typedrop : ftype=%d fstype=%d.\n", ftype, fstype); #endif switch ( ftype ) { case WLAN_FTYPE_MGMT: if ((wlandev->netdev->flags & IFF_PROMISC) || (wlandev->netdev->flags & IFF_ALLMULTI)) { drop = 1; break; } WLAN_LOG_DEBUG(3, "rx'd mgmt:\n"); wlandev->rx.mgmt++; switch( fstype ) { case WLAN_FSTYPE_ASSOCREQ: /* printk("assocreq"); */ wlandev->rx.assocreq++; break; case WLAN_FSTYPE_ASSOCRESP: /* printk("assocresp"); */ wlandev->rx.assocresp++; break; case WLAN_FSTYPE_REASSOCREQ: /* printk("reassocreq"); */ wlandev->rx.reassocreq++; break; case WLAN_FSTYPE_REASSOCRESP: /* printk("reassocresp"); */ wlandev->rx.reassocresp++; break; case WLAN_FSTYPE_PROBEREQ: /* printk("probereq"); */ wlandev->rx.probereq++; break; case WLAN_FSTYPE_PROBERESP: /* printk("proberesp"); */ wlandev->rx.proberesp++; break; case WLAN_FSTYPE_BEACON: /* printk("beacon"); */ wlandev->rx.beacon++; break; case WLAN_FSTYPE_ATIM: /* printk("atim"); */ wlandev->rx.atim++; break; case WLAN_FSTYPE_DISASSOC: /* printk("disassoc"); */ wlandev->rx.disassoc++; break; case WLAN_FSTYPE_AUTHEN: /* printk("authen"); */ wlandev->rx.authen++; break; case WLAN_FSTYPE_DEAUTHEN: /* printk("deauthen"); */ wlandev->rx.deauthen++; break; default: /* printk("unknown"); */ wlandev->rx.mgmt_unknown++; break; } /* printk("\n"); */ drop = 2; break; case WLAN_FTYPE_CTL: if ((wlandev->netdev->flags & IFF_PROMISC) || (wlandev->netdev->flags & IFF_ALLMULTI)) { drop = 1; break; } WLAN_LOG_DEBUG(3, "rx'd ctl:\n"); wlandev->rx.ctl++; switch( fstype ) { case WLAN_FSTYPE_PSPOLL: /* printk("pspoll"); */ wlandev->rx.pspoll++; break; case WLAN_FSTYPE_RTS: /* printk("rts"); */ wlandev->rx.rts++; break; case WLAN_FSTYPE_CTS: /* printk("cts"); */ wlandev->rx.cts++; break; case WLAN_FSTYPE_ACK: /* printk("ack"); */ wlandev->rx.ack++; break; case WLAN_FSTYPE_CFEND: /* printk("cfend"); */ wlandev->rx.cfend++; break; case WLAN_FSTYPE_CFENDCFACK: /* printk("cfendcfack"); */ wlandev->rx.cfendcfack++; break; default: /* printk("unknown"); */ wlandev->rx.ctl_unknown++; break; } /* printk("\n"); */ drop = 2; break; case WLAN_FTYPE_DATA: wlandev->rx.data++; switch( fstype ) { case WLAN_FSTYPE_DATAONLY: wlandev->rx.dataonly++; break; case WLAN_FSTYPE_DATA_CFACK: wlandev->rx.data_cfack++; break; case WLAN_FSTYPE_DATA_CFPOLL: wlandev->rx.data_cfpoll++; break; case WLAN_FSTYPE_DATA_CFACK_CFPOLL: wlandev->rx.data__cfack_cfpoll++; break; case WLAN_FSTYPE_NULL: WLAN_LOG_DEBUG(3, "rx'd data:null\n"); wlandev->rx.null++; break; case WLAN_FSTYPE_CFACK: WLAN_LOG_DEBUG(3, "rx'd data:cfack\n"); wlandev->rx.cfack++; break; case WLAN_FSTYPE_CFPOLL: WLAN_LOG_DEBUG(3, "rx'd data:cfpoll\n"); wlandev->rx.cfpoll++; break; case WLAN_FSTYPE_CFACK_CFPOLL: WLAN_LOG_DEBUG(3, "rx'd data:cfack_cfpoll\n"); wlandev->rx.cfack_cfpoll++; break; default: /* printk("unknown"); */ wlandev->rx.data_unknown++; break; } break; } return drop; }
/* wireless extensions' ioctls */ int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { wlandevice_t *wlandev = (wlandevice_t*)dev->priv; #if WIRELESS_EXT < 13 struct iwreq *iwr = (struct iwreq*)ifr; #endif p80211item_uint32_t mibitem; int err = 0; DBFENTER; mibitem.status = P80211ENUM_msgitem_status_data_ok; if ( wlandev->msdstate != WLAN_MSD_RUNNING ) { err = -ENODEV; goto exit; } WLAN_LOG_DEBUG(1, "Received wireless extension ioctl #%d.\n", cmd); switch (cmd) { #if WIRELESS_EXT < 13 case SIOCSIWNAME: /* unused */ err = (-EOPNOTSUPP); break; case SIOCGIWNAME: /* get name == wireless protocol */ err = p80211wext_giwname(dev, NULL, (char *) &iwr->u, NULL); break; case SIOCSIWNWID: case SIOCGIWNWID: err = (-EOPNOTSUPP); break; case SIOCSIWFREQ: /* set channel */ err = (-EOPNOTSUPP); break; #if 0 if ( (iwf->e == 0) && (iwf->m <= 1000) ) { /* input is a channel number */ chan = iwf->m; } else { /* input is a frequency - search the table */ for (i = 0; i < (6 - iwf->e); i++) mult *= 10; for (i = 0; i < NUM_CHANNELS; i++) if (iwf->m == (prism2wext_channel_freq[i] * mult)) chan = i+1; } /* check for valid channels */ if ((!intval) || (intval > NUM_CHANNELS)) return (-EFAULT); #endif case SIOCGIWFREQ: /* get channel */ err = p80211wext_giwfreq(dev, NULL, &(iwr->u.freq), NULL); break; case SIOCSIWRANGE: case SIOCSIWPRIV: case SIOCSIWAP: /* set access point MAC addresses (BSSID) */ err = (-EOPNOTSUPP); break; case SIOCGIWAP: /* get access point MAC addresses (BSSID) */ err = p80211wext_giwap(dev, NULL, &(iwr->u.ap_addr), NULL); break; #if WIRELESS_EXT > 8 case SIOCSIWMODE: /* set operation mode */ case SIOCSIWESSID: /* set SSID (network name) */ case SIOCSIWRATE: /* set default bit rate (bps) */ err = (-EOPNOTSUPP); break; case SIOCGIWMODE: /* get operation mode */ err = p80211wext_giwmode(dev, NULL, &iwr->u.mode, NULL); break; case SIOCGIWNICKN: /* get node name/nickname */ case SIOCGIWESSID: /* get SSID */ if(iwr->u.essid.pointer) { char ssid[IW_ESSID_MAX_SIZE+1]; memset(ssid, 0, sizeof(ssid)); err = p80211wext_giwessid(dev, NULL, &iwr->u.essid, ssid); if(copy_to_user(iwr->u.essid.pointer, ssid, sizeof(ssid))) err = (-EFAULT); } break; case SIOCGIWRATE: err = p80211wext_giwrate(dev, NULL, &iwr->u.bitrate, NULL); break; case SIOCGIWRTS: err = p80211wext_giwrts(dev, NULL, &iwr->u.rts, NULL); break; case SIOCGIWFRAG: err = p80211wext_giwfrag(dev, NULL, &iwr->u.rts, NULL); break; case SIOCGIWENCODE: if (!capable(CAP_NET_ADMIN)) err = -EPERM; else if (iwr->u.encoding.pointer) { char keybuf[MAX_KEYLEN]; err = p80211wext_giwencode(dev, NULL, &iwr->u.encoding, keybuf); if (copy_to_user(iwr->u.encoding.pointer, keybuf, iwr->u.encoding.length)) err = -EFAULT; } break; case SIOCGIWAPLIST: case SIOCSIWRTS: case SIOCSIWFRAG: case SIOCSIWSENS: case SIOCGIWSENS: case SIOCSIWNICKN: /* set node name/nickname */ case SIOCSIWENCODE: /* set encoding token & mode */ case SIOCSIWSPY: case SIOCGIWSPY: case SIOCSIWPOWER: case SIOCGIWPOWER: case SIOCGIWPRIV: err = (-EOPNOTSUPP); break; case SIOCGIWRANGE: if(iwr->u.data.pointer != NULL) { struct iw_range range; err = p80211wext_giwrange(dev, NULL, &iwr->u.data, (char *) &range); /* Push that up to the caller */ if (copy_to_user(iwr->u.data.pointer, &range, sizeof(range))) err = -EFAULT; } break; #endif /* WIRELESS_EXT > 8 */ #if WIRELESS_EXT > 9 case SIOCSIWTXPOW: err = (-EOPNOTSUPP); break; case SIOCGIWTXPOW: err = p80211wext_giwtxpow(dev, NULL, &iwr->u.txpower, NULL); break; #endif /* WIRELESS_EXT > 9 */ #if WIRELESS_EXT > 10 case SIOCSIWRETRY: err = (-EOPNOTSUPP); break; case SIOCGIWRETRY: err = p80211wext_giwretry(dev, NULL, &iwr->u.retry, NULL); break; #endif /* WIRELESS_EXT > 10 */ #endif /* WIRELESS_EXT <= 12 */ default: err = (-EOPNOTSUPP); break; } exit: DBFEXIT; return (err); }
/*---------------------------------------------------------------- * prism2mgmt_wlansniff * * Start or stop sniffing. * * Arguments: * wlandev wlan device structure * msgp ptr to msg buffer * * Returns: * 0 success and done * <0 success, but we're waiting for something to finish. * >0 an error occurred while handling the message. * Side effects: * * Call context: * process thread (usually) * interrupt ----------------------------------------------------------------*/ int prism2mgmt_wlansniff(wlandevice_t *wlandev, void *msgp) { int result = 0; p80211msg_lnxreq_wlansniff_t *msg = msgp; hfa384x_t *hw = wlandev->priv; u16 word; DBFENTER; msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; switch (msg->enable.data) { case P80211ENUM_truth_false: /* Confirm that we're in monitor mode */ if ( wlandev->netdev->type == ARPHRD_ETHER ) { msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; result = 0; goto exit; } /* Disable monitor mode */ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_DISABLE); if ( result ) { WLAN_LOG_DEBUG(1, "failed to disable monitor mode, result=%d\n", result); goto failed; } /* Disable port 0 */ result = hfa384x_drvr_disable(hw, 0); if ( result ) { WLAN_LOG_DEBUG(1, "failed to disable port 0 after sniffing, result=%d\n", result); goto failed; } /* Clear the driver state */ wlandev->netdev->type = ARPHRD_ETHER; /* Restore the wepflags */ result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFWEPFLAGS, hw->presniff_wepflags); if ( result ) { WLAN_LOG_DEBUG(1, "failed to restore wepflags=0x%04x, result=%d\n", hw->presniff_wepflags, result); goto failed; } /* Set the port to its prior type and enable (if necessary) */ if (hw->presniff_port_type != 0 ) { word = hw->presniff_port_type; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, word); if ( result ) { WLAN_LOG_DEBUG(1, "failed to restore porttype, result=%d\n", result); goto failed; } /* Enable the port */ result = hfa384x_drvr_enable(hw, 0); if ( result ) { WLAN_LOG_DEBUG(1, "failed to enable port to presniff setting, result=%d\n", result); goto failed; } } else { result = hfa384x_drvr_disable(hw, 0); } WLAN_LOG_INFO("monitor mode disabled\n"); msg->resultcode.data = P80211ENUM_resultcode_success; result = 0; goto exit; break; case P80211ENUM_truth_true: /* Disable the port (if enabled), only check Port 0 */ if ( hw->port_enabled[0]) { if (wlandev->netdev->type == ARPHRD_ETHER) { /* Save macport 0 state */ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFPORTTYPE, &(hw->presniff_port_type)); if ( result ) { WLAN_LOG_DEBUG(1,"failed to read porttype, result=%d\n", result); goto failed; } /* Save the wepflags state */ result = hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFWEPFLAGS, &(hw->presniff_wepflags)); if ( result ) { WLAN_LOG_DEBUG(1,"failed to read wepflags, result=%d\n", result); goto failed; } hfa384x_drvr_stop(hw); result = hfa384x_drvr_start(hw); if ( result ) { WLAN_LOG_DEBUG(1, "failed to restart the card for sniffing, result=%d\n", result); goto failed; } } else { /* Disable the port */ result = hfa384x_drvr_disable(hw, 0); if ( result ) { WLAN_LOG_DEBUG(1, "failed to enable port for sniffing, result=%d\n", result); goto failed; } } } else { hw->presniff_port_type = 0; } /* Set the channel we wish to sniff */ word = msg->channel.data; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); hw->sniff_channel=word; if ( result ) { WLAN_LOG_DEBUG(1, "failed to set channel %d, result=%d\n", word, result); goto failed; } /* Now if we're already sniffing, we can skip the rest */ if (wlandev->netdev->type != ARPHRD_ETHER) { /* Set the port type to pIbss */ word = HFA384x_PORTTYPE_PSUEDOIBSS; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, word); if ( result ) { WLAN_LOG_DEBUG(1, "failed to set porttype %d, result=%d\n", word, result); goto failed; } if ((msg->keepwepflags.status == P80211ENUM_msgitem_status_data_ok) && (msg->keepwepflags.data != P80211ENUM_truth_true)) { /* Set the wepflags for no decryption */ word = HFA384x_WEPFLAGS_DISABLE_TXCRYPT | HFA384x_WEPFLAGS_DISABLE_RXCRYPT; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFWEPFLAGS, word); } if ( result ) { WLAN_LOG_DEBUG(1, "failed to set wepflags=0x%04x, result=%d\n", word, result); goto failed; } } /* Do we want to strip the FCS in monitor mode? */ if ((msg->stripfcs.status == P80211ENUM_msgitem_status_data_ok) && (msg->stripfcs.data == P80211ENUM_truth_true)) { hw->sniff_fcs = 0; } else { hw->sniff_fcs = 1; } /* Do we want to truncate the packets? */ if (msg->packet_trunc.status == P80211ENUM_msgitem_status_data_ok) { hw->sniff_truncate = msg->packet_trunc.data; } else { hw->sniff_truncate = 0; } /* Enable the port */ result = hfa384x_drvr_enable(hw, 0); if ( result ) { WLAN_LOG_DEBUG(1, "failed to enable port for sniffing, result=%d\n", result); goto failed; } /* Enable monitor mode */ result = hfa384x_cmd_monitor(hw, HFA384x_MONITOR_ENABLE); if ( result ) { WLAN_LOG_DEBUG(1, "failed to enable monitor mode, result=%d\n", result); goto failed; } if (wlandev->netdev->type == ARPHRD_ETHER) { WLAN_LOG_INFO("monitor mode enabled\n"); } /* Set the driver state */ /* Do we want the prism2 header? */ if ((msg->prismheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->prismheader.data == P80211ENUM_truth_true)) { hw->sniffhdr = 0; wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; } else if ((msg->wlanheader.status == P80211ENUM_msgitem_status_data_ok) && (msg->wlanheader.data == P80211ENUM_truth_true)) { hw->sniffhdr = 1; wlandev->netdev->type = ARPHRD_IEEE80211_PRISM; } else { wlandev->netdev->type = ARPHRD_IEEE80211; } msg->resultcode.data = P80211ENUM_resultcode_success; result = 0; goto exit; break; default: msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; result = 0; goto exit; break; } failed: msg->resultcode.data = P80211ENUM_resultcode_refused; result = 0; exit: DBFEXIT; return result; }
static int prism2_cs_probe(struct pcmcia_device *pdev) { int rval = 0; struct wlandevice *wlandev = NULL; hfa384x_t *hw = NULL; config_info_t socketconf; cisparse_t *parse = NULL; tuple_t tuple; uint8_t buf[64]; int last_fn, last_ret; cistpl_cftable_entry_t dflt = { 0 }; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) dev_link_t *link; #endif DBFENTER; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) /* Set up interrupt type */ pdev->conf.IntType = INT_MEMORY_AND_IO; #else link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); if (link == NULL) return -ENOMEM; memset(link, 0, sizeof(dev_link_t)); link->conf.Vcc = 33; link->conf.IntType = INT_MEMORY_AND_IO; link->handle = pdev; pdev->instance = link; link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; #endif // VCC crap? parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); wlandev = create_wlan(); if (!wlandev || !parse) { WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); rval = -EIO; goto failed; } hw = wlandev->priv; if ( wlan_setup(wlandev) != 0 ) { WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info); rval = -EIO; goto failed; } /* Initialize the hw struct for now */ hfa384x_create(hw, 0, 0, NULL); hw->wlandev = wlandev; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) hw->pdev = pdev; pdev->priv = wlandev; #else hw->link = link; link->priv = wlandev; #endif tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, parse)); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.ConfigBase = parse->config.base; pdev->conf.Present = parse->config.rmask[0]; #else link->conf.ConfigBase = parse->config.base; link->conf.Present = parse->config.rmask[0]; link->conf.Vcc = socketconf.Vcc; #endif CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &socketconf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple)); for (;;) { cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); CFG_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple)); CFG_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) goto next_entry; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.ConfigIndex = cfg->index; #else link->conf.ConfigIndex = cfg->index; #endif /* Does this card need audio output? */ if (cfg->flags & CISTPL_CFTABLE_AUDIO) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.Attributes |= CONF_ENABLE_SPKR; pdev->conf.Status = CCSR_AUDIO_ENA; #else link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; #endif } /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (socketconf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000 && !prism2_ignorevcc) { WLAN_LOG_DEBUG(1, " Vcc mismatch - skipping" " this entry\n"); goto next_entry; } } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) { if (socketconf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] / 10000 && !prism2_ignorevcc) { WLAN_LOG_DEBUG(1, " Vcc (default) mismatch " "- skipping this entry\n"); goto next_entry; } } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; #else link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; #endif } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; #else link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; #endif } /* Do we need to allocate an interrupt? */ /* HACK: due to a bad CIS....we ALWAYS need an interrupt */ /* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->conf.Attributes |= CONF_ENABLE_IRQ; #else link->conf.Attributes |= CONF_ENABLE_IRQ; #endif /* IO window settings */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->io.NumPorts1 = pdev->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; pdev->io.BasePort1 = io->win[0].base; if ( pdev->io.BasePort1 != 0 ) { WLAN_LOG_WARNING( "Brain damaged CIS: hard coded iobase=" "0x%x, try letting pcmcia_cs decide...\n", pdev->io.BasePort1 ); pdev->io.BasePort1 = 0; } pdev->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { pdev->io.Attributes2 = pdev->io.Attributes1; pdev->io.BasePort2 = io->win[1].base; pdev->io.NumPorts2 = io->win[1].len; } } /* This reserves IO space but doesn't actually enable it */ CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &pdev->io)); #else link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.BasePort1 = io->win[0].base; if ( link->io.BasePort1 != 0 ) { WLAN_LOG_WARNING( "Brain damaged CIS: hard coded iobase=" "0x%x, try letting pcmcia_cs decide...\n", link->io.BasePort1 ); link->io.BasePort1 = 0; } link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } } /* This reserves IO space but doesn't actually enable it */ CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &link->io)); #endif /* If we got this far, we're cool! */ break; next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple)); } /* Let pcmcia know the device name */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->dev_node = &hw->node; #else link->dev = &hw->node; #endif /* Register the network device and get assigned a name */ SET_MODULE_OWNER(wlandev->netdev); SET_NETDEV_DEV(wlandev->netdev, &handle_to_dev(pdev)); if (register_wlandev(wlandev) != 0) { WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n"); goto failed; } strcpy(hw->node.dev_name, wlandev->name); /* Allocate an interrupt line. Note that this does not assign a */ /* handler to the interrupt, unless the 'Handler' member of the */ /* irq structure is initialized. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) if (pdev->conf.Attributes & CONF_ENABLE_IRQ) { pdev->irq.IRQInfo1 = IRQ_LEVEL_ID; pdev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; pdev->irq.Handler = hfa384x_interrupt; pdev->irq.Instance = wlandev; CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq)); } #else if (link->conf.Attributes & CONF_ENABLE_IRQ) { link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Handler = hfa384x_interrupt; link->irq.Instance = wlandev; CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &link->irq)); } #endif /* This actually configures the PCMCIA socket -- setting up */ /* the I/O windows and the interrupt mapping, and putting the */ /* card and host interface into "Memory and IO" mode. */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf)); #else CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &link->conf)); #endif /* Fill the netdevice with this info */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) wlandev->netdev->irq = pdev->irq.AssignedIRQ; wlandev->netdev->base_addr = pdev->io.BasePort1; #else wlandev->netdev->irq = link->irq.AssignedIRQ; wlandev->netdev->base_addr = link->io.BasePort1; #endif /* And the rest of the hw structure */ hw->irq = wlandev->netdev->irq; hw->iobase = wlandev->netdev->base_addr; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) link->state |= DEV_CONFIG; link->state &= ~DEV_CONFIG_PENDING; #endif /* And now we're done! */ wlandev->msdstate = WLAN_MSD_HWPRESENT; goto done; cs_failed: cs_error(pdev, last_fn, last_ret); failed: // wlandev, hw, etc etc.. #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) pdev->priv = NULL; #else pdev->instance = NULL; if (link) { link->priv = NULL; kfree(link); } #endif if (wlandev) { wlan_unsetup(wlandev); if (wlandev->priv) { hw = wlandev->priv; wlandev->priv = NULL; if (hw) { hfa384x_destroy(hw); kfree(hw); } } kfree(wlandev); } done: if (parse) kfree(parse); DBFEXIT; return rval; }
/*---------------------------------------------------------------- * prism2mgmt_start * * Start a BSS. Any station can do this for IBSS, only AP for ESS. * * Arguments: * wlandev wlan device structure * msgp ptr to msg buffer * * Returns: * 0 success and done * <0 success, but we're waiting for something to finish. * >0 an error occurred while handling the message. * Side effects: * * Call context: * process thread (usually) * interrupt ----------------------------------------------------------------*/ int prism2mgmt_start(wlandevice_t *wlandev, void *msgp) { int result = 0; hfa384x_t *hw = wlandev->priv; p80211msg_dot11req_start_t *msg = msgp; p80211pstrd_t *pstr; u8 bytebuf[80]; hfa384x_bytestr_t *p2bytestr = (hfa384x_bytestr_t*)bytebuf; u16 word; DBFENTER; wlandev->macmode = WLAN_MACMODE_NONE; /* Set the SSID */ memcpy(&wlandev->ssid, &msg->ssid.data, sizeof(msg->ssid.data)); /*** ADHOC IBSS ***/ /* see if current f/w is less than 8c3 */ if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major, hw->ident_sta_fw.minor, hw->ident_sta_fw.variant) < HFA384x_FIRMWARE_VERSION(0,8,3)) { /* Ad-Hoc not quite supported on Prism2 */ msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; msg->resultcode.data = P80211ENUM_resultcode_not_supported; goto done; } msg->resultcode.status = P80211ENUM_msgitem_status_data_ok; /*** STATION ***/ /* Set the REQUIRED config items */ /* SSID */ pstr = (p80211pstrd_t*)&(msg->ssid.data); prism2mgmt_pstr2bytestr(p2bytestr, pstr); result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFOWNSSID, bytebuf, HFA384x_RID_CNFOWNSSID_LEN); if ( result ) { WLAN_LOG_ERROR("Failed to set CnfOwnSSID\n"); goto failed; } result = hfa384x_drvr_setconfig( hw, HFA384x_RID_CNFDESIREDSSID, bytebuf, HFA384x_RID_CNFDESIREDSSID_LEN); if ( result ) { WLAN_LOG_ERROR("Failed to set CnfDesiredSSID\n"); goto failed; } /* bsstype - we use the default in the ap firmware */ /* IBSS port */ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, 0); /* beacon period */ word = msg->beaconperiod.data; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAPBCNint, word); if ( result ) { WLAN_LOG_ERROR("Failed to set beacon period=%d.\n", word); goto failed; } /* dschannel */ word = msg->dschannel.data; result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFOWNCHANNEL, word); if ( result ) { WLAN_LOG_ERROR("Failed to set channel=%d.\n", word); goto failed; } /* Basic rates */ word = p80211rate_to_p2bit(msg->basicrate1.data); if ( msg->basicrate2.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate2.data); } if ( msg->basicrate3.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate3.data); } if ( msg->basicrate4.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate4.data); } if ( msg->basicrate5.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate5.data); } if ( msg->basicrate6.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate6.data); } if ( msg->basicrate7.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate7.data); } if ( msg->basicrate8.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->basicrate8.data); } result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFBASICRATES, word); if ( result ) { WLAN_LOG_ERROR("Failed to set basicrates=%d.\n", word); goto failed; } /* Operational rates (supprates and txratecontrol) */ word = p80211rate_to_p2bit(msg->operationalrate1.data); if ( msg->operationalrate2.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate2.data); } if ( msg->operationalrate3.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate3.data); } if ( msg->operationalrate4.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate4.data); } if ( msg->operationalrate5.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate5.data); } if ( msg->operationalrate6.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate6.data); } if ( msg->operationalrate7.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate7.data); } if ( msg->operationalrate8.status == P80211ENUM_msgitem_status_data_ok ) { word |= p80211rate_to_p2bit(msg->operationalrate8.data); } result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFSUPPRATES, word); if ( result ) { WLAN_LOG_ERROR("Failed to set supprates=%d.\n", word); goto failed; } result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, word); if ( result ) { WLAN_LOG_ERROR("Failed to set txrates=%d.\n", word); goto failed; } /* Set the macmode so the frame setup code knows what to do */ if ( msg->bsstype.data == P80211ENUM_bsstype_independent ) { wlandev->macmode = WLAN_MACMODE_IBSS_STA; /* lets extend the data length a bit */ hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, 2304); } /* Enable the Port */ result = hfa384x_drvr_enable(hw, 0); if ( result ) { WLAN_LOG_ERROR("Enable macport failed, result=%d.\n", result); goto failed; } msg->resultcode.data = P80211ENUM_resultcode_success; goto done; failed: WLAN_LOG_DEBUG(1, "Failed to set a config option, result=%d\n", result); msg->resultcode.data = P80211ENUM_resultcode_invalid_parameters; done: result = 0; DBFEXIT; return result; }
/*---------------------------------------------------------------- * prism2mgmt_scan_results * * Retrieve the BSS description for one of the BSSs identified in * a scan. * * Arguments: * wlandev wlan device structure * msgp ptr to msg buffer * * Returns: * 0 success and done * <0 success, but we're waiting for something to finish. * >0 an error occurred while handling the message. * Side effects: * * Call context: * process thread (usually) * interrupt ----------------------------------------------------------------*/ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp) { int result = 0; p80211msg_dot11req_scan_results_t *req; hfa384x_t *hw = wlandev->priv; hfa384x_HScanResultSub_t *item = NULL; int count; DBFENTER; req = (p80211msg_dot11req_scan_results_t *) msgp; req->resultcode.status = P80211ENUM_msgitem_status_data_ok; if (! hw->scanresults) { WLAN_LOG_ERROR("dot11req_scan_results can only be used after a successful dot11req_scan.\n"); result = 2; req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; goto exit; } count = (hw->scanresults->framelen - 3) / 32; if (count > 32) count = 32; if (req->bssindex.data >= count) { WLAN_LOG_DEBUG(0, "requested index (%d) out of range (%d)\n", req->bssindex.data, count); result = 2; req->resultcode.data = P80211ENUM_resultcode_invalid_parameters; goto exit; } item = &(hw->scanresults->info.hscanresult.result[req->bssindex.data]); /* signal and noise */ req->signal.status = P80211ENUM_msgitem_status_data_ok; req->noise.status = P80211ENUM_msgitem_status_data_ok; req->signal.data = hfa384x2host_16(item->sl); req->noise.data = hfa384x2host_16(item->anl); /* BSSID */ req->bssid.status = P80211ENUM_msgitem_status_data_ok; req->bssid.data.len = WLAN_BSSID_LEN; memcpy(req->bssid.data.data, item->bssid, WLAN_BSSID_LEN); /* SSID */ req->ssid.status = P80211ENUM_msgitem_status_data_ok; req->ssid.data.len = hfa384x2host_16(item->ssid.len); memcpy(req->ssid.data.data, item->ssid.data, req->ssid.data.len); /* supported rates */ for (count = 0; count < 10 ; count++) if (item->supprates[count] == 0) break; #define REQBASICRATE(N) \ if ((count >= N) && DOT11_RATE5_ISBASIC_GET(item->supprates[(N)-1])) { \ req->basicrate ## N .data = item->supprates[(N)-1]; \ req->basicrate ## N .status = P80211ENUM_msgitem_status_data_ok; \ } REQBASICRATE(1); REQBASICRATE(2); REQBASICRATE(3); REQBASICRATE(4); REQBASICRATE(5); REQBASICRATE(6); REQBASICRATE(7); REQBASICRATE(8); #define REQSUPPRATE(N) \ if (count >= N) { \ req->supprate ## N .data = item->supprates[(N)-1]; \ req->supprate ## N .status = P80211ENUM_msgitem_status_data_ok; \ } REQSUPPRATE(1); REQSUPPRATE(2); REQSUPPRATE(3); REQSUPPRATE(4); REQSUPPRATE(5); REQSUPPRATE(6); REQSUPPRATE(7); REQSUPPRATE(8); /* beacon period */ req->beaconperiod.status = P80211ENUM_msgitem_status_data_ok; req->beaconperiod.data = hfa384x2host_16(item->bcnint); /* timestamps */ req->timestamp.status = P80211ENUM_msgitem_status_data_ok; req->timestamp.data = jiffies; req->localtime.status = P80211ENUM_msgitem_status_data_ok; req->localtime.data = jiffies; /* atim window */ req->ibssatimwindow.status = P80211ENUM_msgitem_status_data_ok; req->ibssatimwindow.data = hfa384x2host_16(item->atim); /* Channel */ req->dschannel.status = P80211ENUM_msgitem_status_data_ok; req->dschannel.data = hfa384x2host_16(item->chid); /* capinfo bits */ count = hfa384x2host_16(item->capinfo); /* privacy flag */ req->privacy.status = P80211ENUM_msgitem_status_data_ok; req->privacy.data = WLAN_GET_MGMT_CAP_INFO_PRIVACY(count); /* cfpollable */ req->cfpollable.status = P80211ENUM_msgitem_status_data_ok; req->cfpollable.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLABLE(count); /* cfpollreq */ req->cfpollreq.status = P80211ENUM_msgitem_status_data_ok; req->cfpollreq.data = WLAN_GET_MGMT_CAP_INFO_CFPOLLREQ(count); /* bsstype */ req->bsstype.status = P80211ENUM_msgitem_status_data_ok; req->bsstype.data = (WLAN_GET_MGMT_CAP_INFO_ESS(count)) ? P80211ENUM_bsstype_infrastructure : P80211ENUM_bsstype_independent; // item->proberesp_rate /* req->fhdwelltime req->fhhopset req->fhhoppattern req->fhhopindex req->cfpdurremaining */ result = 0; req->resultcode.data = P80211ENUM_resultcode_success; exit: DBFEXIT; return result; }
/*---------------------------------------------------------------- * prism2sta_event * * Handler for card services events. * * Arguments: * event The event code * priority hi/low - REMOVAL is the only hi * args ptr to card services struct containing info about * pcmcia status * * Returns: * Zero on success, non-zero otherwise * * Side effects: * * * Call context: * Both interrupt and process thread, depends on the event. ----------------------------------------------------------------*/ static int prism2sta_event ( event_t event, int priority, event_callback_args_t *args) { int result = 0; dev_link_t *link = (dev_link_t *) args->client_data; wlandevice_t *wlandev = (wlandevice_t*)link->priv; hfa384x_t *hw = NULL; DBFENTER; if (wlandev) hw = wlandev->priv; switch (event) { case CS_EVENT_CARD_INSERTION: WLAN_LOG_DEBUG(5,"event is INSERTION\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; prism2sta_config(link); if (!(link->state & DEV_CONFIG)) { wlandev->netdev->irq = 0; WLAN_LOG_ERROR( "%s: Initialization failed!\n", dev_info); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } /* Fill in the rest of the hw struct */ hw->irq = wlandev->netdev->irq; hw->iobase = wlandev->netdev->base_addr; hw->link = link; if (prism2_doreset) { result = hfa384x_corereset(hw, prism2_reset_holdtime, prism2_reset_settletime, 0); if ( result ) { WLAN_LOG_ERROR( "corereset() failed, result=%d.\n", result); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } } #if 0 /* * TODO: test_hostif() not implemented yet. */ result = hfa384x_test_hostif(hw); if (result) { WLAN_LOG_ERROR( "test_hostif() failed, result=%d.\n", result); wlandev->msdstate = WLAN_MSD_HWFAIL; break; } #endif wlandev->msdstate = WLAN_MSD_HWPRESENT; break; case CS_EVENT_CARD_REMOVAL: WLAN_LOG_DEBUG(5,"event is REMOVAL\n"); link->state &= ~DEV_PRESENT; if (wlandev) { p80211netdev_hwremoved(wlandev); } #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) if (link->state & DEV_CONFIG) { link->release.expires = jiffies + (HZ/20); add_timer(&link->release); } #endif break; case CS_EVENT_RESET_REQUEST: WLAN_LOG_DEBUG(5,"event is RESET_REQUEST\n"); WLAN_LOG_NOTICE( "prism2 card reset not supported " "due to post-reset user mode configuration " "requirements.\n"); WLAN_LOG_NOTICE( " From user mode, use " "'cardctl suspend;cardctl resume' " "instead.\n"); break; case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_CARD_RESET: WLAN_LOG_WARNING("Rx'd CS_EVENT_RESET_xxx, should not " "be possible since RESET_REQUEST was denied.\n"); break; case CS_EVENT_PM_SUSPEND: WLAN_LOG_DEBUG(5,"event is SUSPEND\n"); link->state |= DEV_SUSPEND; if (link->state & DEV_CONFIG) { prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable); pcmcia_release_configuration(link->handle); } break; case CS_EVENT_PM_RESUME: WLAN_LOG_DEBUG(5,"event is RESUME\n"); link->state &= ~DEV_SUSPEND; if (link->state & DEV_CONFIG) { pcmcia_request_configuration(link->handle, &link->conf); } break; } DBFEXIT; return 0; /* noone else does anthing with the return value */ }
int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis) { int result = 0; conf_reg_t reg; UINT8 corsave; DBFENTER; WLAN_LOG_DEBUG(3, "Doing reset via CardServices().\n"); /* Collect COR */ reg.Function = 0; reg.Action = CS_READ; reg.Offset = CISREG_COR; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) result = pcmcia_access_configuration_register(hw->pdev, ®); #else result = pcmcia_access_configuration_register( hw->link->handle, ®); #endif if (result != CS_SUCCESS ) { WLAN_LOG_ERROR( ":0: AccessConfigurationRegister(CS_READ) failed," "result=%d.\n", result); result = -EIO; } corsave = reg.Value; /* Write reset bit (BIT7) */ reg.Value |= BIT7; reg.Action = CS_WRITE; reg.Offset = CISREG_COR; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) result = pcmcia_access_configuration_register(hw->pdev, ®); #else result = pcmcia_access_configuration_register( hw->link->handle, ®); #endif if (result != CS_SUCCESS ) { WLAN_LOG_ERROR( ":1: AccessConfigurationRegister(CS_WRITE) failed," "result=%d.\n", result); result = -EIO; } /* Hold for holdtime */ mdelay(holdtime); if (genesis) { reg.Value = genesis; reg.Action = CS_WRITE; reg.Offset = CISREG_CCSR; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) result = pcmcia_access_configuration_register(hw->pdev, ®); #else result = pcmcia_access_configuration_register( hw->link->handle, ®); #endif if (result != CS_SUCCESS ) { WLAN_LOG_ERROR( ":1: AccessConfigurationRegister(CS_WRITE) failed," "result=%d.\n", result); result = -EIO; } } /* Hold for holdtime */ mdelay(holdtime); /* Clear reset bit */ reg.Value &= ~BIT7; reg.Action = CS_WRITE; reg.Offset = CISREG_COR; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) result = pcmcia_access_configuration_register(hw->pdev, ®); #else result = pcmcia_access_configuration_register( hw->link->handle, ®); #endif if (result != CS_SUCCESS ) { WLAN_LOG_ERROR( ":2: AccessConfigurationRegister(CS_WRITE) failed," "result=%d.\n", result); result = -EIO; goto done; } /* Wait for settletime */ mdelay(settletime); /* Set non-reset bits back what they were */ reg.Value = corsave; reg.Action = CS_WRITE; reg.Offset = CISREG_COR; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16) result = pcmcia_access_configuration_register(hw->pdev, ®); #else result = pcmcia_access_configuration_register( hw->link->handle, ®); #endif if (result != CS_SUCCESS ) { WLAN_LOG_ERROR( ":2: AccessConfigurationRegister(CS_WRITE) failed," "result=%d.\n", result); result = -EIO; goto done; } done: DBFEXIT; return result; }
/*---------------------------------------------------------------- * prism2sta_probe_plx * * Probe routine called when a PCI device w/ matching ID is found. * This PLX implementation uses the following map: * BAR0: Unused * BAR1: ???? * BAR2: PCMCIA attribute memory * BAR3: PCMCIA i/o space * Here's the sequence: * - Allocate the PCI resources. * - Read the PCMCIA attribute memory to make sure we have a WLAN card * - Reset the MAC using the PCMCIA COR * - Initialize the netdev and wlan data * - Initialize the MAC * * Arguments: * pdev ptr to pci device structure containing info about * pci configuration. * id ptr to the device id entry that matched this device. * * Returns: * zero - success * negative - failed * * Side effects: * * * Call context: * process thread * ----------------------------------------------------------------*/ static int __devinit prism2sta_probe_plx( struct pci_dev *pdev, const struct pci_device_id *id) { int result; phys_t pccard_ioaddr; phys_t pccard_attr_mem; unsigned int pccard_attr_len; void __iomem *attr_mem = NULL; UINT32 plx_addr; wlandevice_t *wlandev = NULL; hfa384x_t *hw = NULL; int reg; u32 regic; if (pci_enable_device(pdev)) return -EIO; /* TMC7160 boards are special */ if ((pdev->vendor == PCIVENDOR_NDC) && (pdev->device == PCIDEVICE_NCP130_ASIC)) { unsigned long delay; pccard_attr_mem = 0; pccard_ioaddr = pci_resource_start(pdev, 1); outb(0x45, pccard_ioaddr); delay = jiffies + 1*HZ; while (time_before(jiffies, delay)); if (inb(pccard_ioaddr) != 0x45) { WLAN_LOG_ERROR("Initialize the TMC7160 failed. (0x%x)\n", inb(pccard_ioaddr)); return -EIO; } pccard_ioaddr = pci_resource_start(pdev, 2); prism2_doreset = 0; WLAN_LOG_INFO("NDC NCP130 with TMC716(ASIC) PCI interface device found at io:0x%x, irq:%d\n", pccard_ioaddr, pdev->irq); goto init; } /* Collect the resource requirements */ pccard_attr_mem = pci_resource_start(pdev, 2); pccard_attr_len = pci_resource_len(pdev, 2); if (pccard_attr_len < PLX_MIN_ATTR_LEN) return -EIO; pccard_ioaddr = pci_resource_start(pdev, 3); /* bjoern: We need to tell the card to enable interrupts, in * case the serial eprom didn't do this already. See the * PLX9052 data book, p8-1 and 8-24 for reference. * [MSM]: This bit of code came from the orinoco_cs driver. */ plx_addr = pci_resource_start(pdev, 1); regic = 0; regic = inl(plx_addr+PLX_INTCSR); if(regic & PLX_INTCSR_INTEN) { WLAN_LOG_DEBUG(1, "%s: Local Interrupt already enabled\n", dev_info); } else { regic |= PLX_INTCSR_INTEN; outl(regic, plx_addr+PLX_INTCSR); regic = inl(plx_addr+PLX_INTCSR); if(!(regic & PLX_INTCSR_INTEN)) { WLAN_LOG_ERROR( "%s: Couldn't enable Local Interrupts\n", dev_info); return -EIO; } } /* These assignments are here in case of future mappings for * io space and irq that might be similar to ioremap */ if (!request_mem_region(pccard_attr_mem, pci_resource_len(pdev, 2), "Prism2")) { WLAN_LOG_ERROR("%s: Couldn't reserve PCI memory region\n", dev_info); return -EIO; } attr_mem = ioremap(pccard_attr_mem, pccard_attr_len); WLAN_LOG_INFO("A PLX PCI/PCMCIA interface device found, " "phymem:0x%llx, phyio=0x%x, irq:%d, " "mem: 0x%lx\n", (unsigned long long)pccard_attr_mem, pccard_ioaddr, pdev->irq, (unsigned long)attr_mem); /* Verify whether PC card is present. * [MSM] This needs improvement, the right thing to do is * probably to walk the CIS looking for the vendor and product * IDs. It would be nice if this could be tied in with the * etc/pcmcia/wlan-ng.conf file. Any volunteers? ;-) */ if ( readb(attr_mem + 0) != 0x01 || readb(attr_mem + 2) != 0x03 || readb(attr_mem + 4) != 0x00 || readb(attr_mem + 6) != 0x00 || readb(attr_mem + 8) != 0xFF || readb(attr_mem + 10) != 0x17 || readb(attr_mem + 12) != 0x04 || readb(attr_mem + 14) != 0x67) { WLAN_LOG_ERROR("Prism2 PC card CIS is invalid.\n"); return -EIO; } WLAN_LOG_INFO("A PCMCIA WLAN adapter was found.\n"); /* Write COR to enable PC card */ writeb(COR_VALUE, attr_mem + COR_OFFSET); reg = readb(attr_mem + COR_OFFSET); init: /* * Now do everything the same as a PCI device * [MSM] TODO: We could probably factor this out of pcmcia/pci/plx * and perhaps usb. Perhaps a task for another day....... */ if ((wlandev = create_wlan()) == NULL) { WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info); result = -EIO; goto failed; } hw = wlandev->priv; if ( wlan_setup(wlandev) != 0 ) { WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info); result = -EIO; goto failed; } /* Setup netdevice's ability to report resources * Note: the netdevice was allocated by wlan_setup() */ wlandev->netdev->irq = pdev->irq; wlandev->netdev->base_addr = pccard_ioaddr; wlandev->netdev->mem_start = (unsigned long)attr_mem; wlandev->netdev->mem_end = (unsigned long)attr_mem + pci_resource_len(pdev, 0); /* Initialize the hw data */ hfa384x_create(hw, wlandev->netdev->irq, pccard_ioaddr, attr_mem); hw->wlandev = wlandev; /* Register the wlandev, this gets us a name and registers the * linux netdevice. */ SET_MODULE_OWNER(wlandev->netdev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) SET_NETDEV_DEV(wlandev->netdev, &(pdev->dev)); #endif if ( register_wlandev(wlandev) != 0 ) { WLAN_LOG_ERROR("%s: register_wlandev() failed.\n", dev_info); result = -EIO; goto failed; } #if 0 /* TODO: Move this and an irq test into an hfa384x_testif() routine. */ outw(PRISM2STA_MAGIC, HFA384x_SWSUPPORT(wlandev->netdev->base_addr)); reg=inw( HFA384x_SWSUPPORT(wlandev->netdev->base_addr)); if ( reg != PRISM2STA_MAGIC ) { WLAN_LOG_ERROR("MAC register access test failed!\n"); result = -EIO; goto failed; } #endif /* Do a chip-level reset on the MAC */ if (prism2_doreset) { result = hfa384x_corereset(hw, prism2_reset_holdtime, prism2_reset_settletime, 0); if (result != 0) { unregister_wlandev(wlandev); hfa384x_destroy(hw); WLAN_LOG_ERROR( "%s: hfa384x_corereset() failed.\n", dev_info); result = -EIO; goto failed; } } pci_set_drvdata(pdev, wlandev); /* Shouldn't actually hook up the IRQ until we * _know_ things are alright. A test routine would help. */ request_irq(wlandev->netdev->irq, hfa384x_interrupt, SA_SHIRQ, wlandev->name, wlandev); wlandev->msdstate = WLAN_MSD_HWPRESENT; result = 0; goto done; failed: pci_set_drvdata(pdev, NULL); if (wlandev) kfree(wlandev); if (hw) kfree(hw); if (attr_mem) iounmap(attr_mem); pci_release_regions(pdev); pci_disable_device(pdev); done: DBFEXIT; return result; }
void prism2sta_config(dev_link_t *link) { client_handle_t handle; wlandevice_t *wlandev; hfa384x_t *hw; int last_fn; int last_ret; tuple_t tuple; cisparse_t parse; config_info_t socketconf; UINT8 buf[64]; int minVcc = 0; int maxVcc = 0; cistpl_cftable_entry_t dflt = { 0 }; DBFENTER; handle = link->handle; wlandev = (wlandevice_t*)link->priv; hw = wlandev->priv; /* Collect the config register info */ tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Configure card */ link->state |= DEV_CONFIG; /* Acquire the current socket config (need Vcc setting) */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &socketconf)); /* Loop through the config table entries until we find one that works */ /* Assumes a complete and valid CIS */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); CFG_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); if (cfg->index == 0) goto next_entry; link->conf.ConfigIndex = cfg->index; /* Lets print out the Vcc that the controller+pcmcia-cs set * for us, cause that's what we're going to use. */ WLAN_LOG_DEBUG(1,"Initial Vcc=%d/10v\n", socketconf.Vcc); if (prism2_ignorevcc) { link->conf.Vcc = socketconf.Vcc; goto skipvcc; } /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { WLAN_LOG_DEBUG(1, "Vcc obtained from curtupl.VNOM\n"); minVcc = maxVcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { WLAN_LOG_DEBUG(1, "Vcc set from dflt.VNOM\n"); minVcc = maxVcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; } else if ((cfg->vcc.present & (1<<CISTPL_POWER_VMAX)) && (cfg->vcc.present & (1<<CISTPL_POWER_VMIN)) ) { WLAN_LOG_DEBUG(1, "Vcc set from curtupl(VMIN,VMAX)\n"); minVcc = cfg->vcc.param[CISTPL_POWER_VMIN]/10000; maxVcc = cfg->vcc.param[CISTPL_POWER_VMAX]/10000; } else if ((dflt.vcc.present & (1<<CISTPL_POWER_VMAX)) && (dflt.vcc.present & (1<<CISTPL_POWER_VMIN)) ) { WLAN_LOG_DEBUG(1, "Vcc set from dflt(VMIN,VMAX)\n"); minVcc = dflt.vcc.param[CISTPL_POWER_VMIN]/10000; maxVcc = dflt.vcc.param[CISTPL_POWER_VMAX]/10000; } if ( socketconf.Vcc >= minVcc && socketconf.Vcc <= maxVcc) { link->conf.Vcc = socketconf.Vcc; } else { /* [MSM]: Note that I've given up trying to change * the Vcc if a change is indicated. It seems the * system&socketcontroller&card vendors can't seem * to get it right, so I'm tired of trying to hack * my way around it. pcmcia-cs does its best using * the voltage sense pins but sometimes the controller * lies. Then, even if we have a good read on the VS * pins, some system designs will silently ignore our * requests to set the voltage. Additionally, some * vendors have 3.3v indicated on their sense pins, * but 5v specified in the CIS or vice-versa. I've * had it. My only recommendation is "let the buyer * beware". Your system might supply 5v to a 3v card * (possibly causing damage) or a 3v capable system * might supply 5v to a 3v capable card (wasting * precious battery life). * My only recommendation (if you care) is to get * yourself an extender card (I don't know where, I * have only one myself) and a meter and test it for * yourself. */ goto next_entry; } skipvcc: WLAN_LOG_DEBUG(1, "link->conf.Vcc=%d\n", link->conf.Vcc); /* Do we need to allocate an interrupt? */ /* HACK: due to a bad CIS....we ALWAYS need an interrupt */ /* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */ link->conf.Attributes |= CONF_ENABLE_IRQ; /* IO window settings */ link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.BasePort1 = io->win[0].base; if ( link->io.BasePort1 != 0 ) { WLAN_LOG_WARNING( "Brain damaged CIS: hard coded iobase=" "0x%x, try letting pcmcia_cs decide...\n", link->io.BasePort1 ); link->io.BasePort1 = 0; } link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } } /* This reserves IO space but doesn't actually enable it */ CFG_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); /* If we got this far, we're cool! */ break; next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); } /* Allocate an interrupt line. Note that this does not assign a */ /* handler to the interrupt, unless the 'Handler' member of the */ /* irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) { #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ) int i; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i=0; i<4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; #else link->irq.IRQInfo1 = IRQ_LEVEL_ID; #endif link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Handler = hfa384x_interrupt; link->irq.Instance = wlandev; CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); } /* This actually configures the PCMCIA socket -- setting up */ /* the I/O windows and the interrupt mapping, and putting the */ /* card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); /* Fill the netdevice with this info */ wlandev->netdev->irq = link->irq.AssignedIRQ; wlandev->netdev->base_addr = link->io.BasePort1; /* Report what we've done */ WLAN_LOG_INFO("%s: index 0x%02x: Vcc %d.%d", dev_info, link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10); if (link->conf.Vpp1) printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); if (link->io.NumPorts2) printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1); printk("\n"); link->state &= ~DEV_CONFIG_PENDING; /* Let pcmcia know the device name */ link->dev = &hw->node; /* Register the network device and get assigned a name */ SET_MODULE_OWNER(wlandev->netdev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) ) SET_NETDEV_DEV(wlandev->netdev, &handle_to_dev(link->handle)); #endif if (register_wlandev(wlandev) != 0) { WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n"); goto failed; } strcpy(hw->node.dev_name, wlandev->name); /* Any device custom config/query stuff should be done here */ /* For a netdevice, we should at least grab the mac address */ return; cs_failed: cs_error(link->handle, last_fn, last_ret); WLAN_LOG_ERROR("NextTuple failure? It's probably a Vcc mismatch.\n"); failed: prism2sta_release((u_long)link); return; }
/* Helper to translate scan into Wireless Extensions scan results. * Inspired by the prism54 code, which was in turn inspired by the * airo driver code. */ static char * wext_translate_bss(char *current_ev, char *end_buf, p80211msg_dot11req_scan_results_t *bss) { struct iw_event iwe; /* Temporary buffer */ /* The first entry must be the MAC address */ memcpy(iwe.u.ap_addr.sa_data, bss->bssid.data.data, WLAN_BSSID_LEN); iwe.u.ap_addr.sa_family = ARPHRD_ETHER; iwe.cmd = SIOCGIWAP; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* The following entries will be displayed in the same order we give them */ /* The ESSID. */ if (bss->ssid.data.len > 0) { char essid[IW_ESSID_MAX_SIZE + 1]; int size; size = wlan_min(IW_ESSID_MAX_SIZE, bss->ssid.data.len); memset(&essid, 0, sizeof (essid)); memcpy(&essid, bss->ssid.data.data, size); WLAN_LOG_DEBUG(1, " essid size = %d\n", size); iwe.u.data.length = size; iwe.u.data.flags = 1; iwe.cmd = SIOCGIWESSID; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, &essid[0]); WLAN_LOG_DEBUG(1, " essid size OK.\n"); } switch (bss->bsstype.data) { case P80211ENUM_bsstype_infrastructure: iwe.u.mode = IW_MODE_MASTER; break; case P80211ENUM_bsstype_independent: iwe.u.mode = IW_MODE_ADHOC; break; default: iwe.u.mode = 0; break; } iwe.cmd = SIOCGIWMODE; if (iwe.u.mode) current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); /* Encryption capability */ if (bss->privacy.data == P80211ENUM_truth_true) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; iwe.cmd = SIOCGIWENCODE; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); /* Add frequency. (short) bss->channel is the frequency in MHz */ iwe.u.freq.m = bss->dschannel.data; iwe.u.freq.e = 0; iwe.cmd = SIOCGIWFREQ; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); /* Add quality statistics */ iwe.u.qual.level = bss->signal.data; iwe.u.qual.noise = bss->noise.data; /* do a simple SNR for quality */ iwe.u.qual.qual = bss->signal.data - bss->noise.data; iwe.cmd = IWEVQUAL; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); return current_ev; }