Example #1
0
/*----------------------------------------------------------------
* 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;
}
Example #2
0
/*----------------------------------------------------------------
* 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 */
}
Example #4
0
/*----------------------------------------------------------------
* 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;
}
Example #5
0
/*----------------------------------------------------------------
* 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;
}
Example #6
0
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;
}
Example #7
0
/*----------------------------------------------------------------
* 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;
}
Example #8
0
/*----------------------------------------------------------------
* 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;
}
Example #9
0
/*----------------------------------------------------------------
* 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;
}
Example #10
0
/* 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;
}
Example #12
0
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;
}
Example #15
0
/*----------------------------------------------------------------
* 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 */
}
Example #16
0
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, &reg);
#else
	result = pcmcia_access_configuration_register(
			hw->link->handle,
			&reg);
#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, &reg);
#else
	result = pcmcia_access_configuration_register(
			hw->link->handle,
			&reg);
#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, &reg);
#else
		result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#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, &reg);
#else
	result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#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, &reg);
#else
	result = pcmcia_access_configuration_register(
				      hw->link->handle,
				      &reg);
#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;
}
Example #17
0
/*----------------------------------------------------------------
* 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;
}
Example #18
0
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;
}