⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zd1201.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* Skip the 4 bytes header (RID length and RID) */		if(i == 0) {			pdata += 8;			actual_length -= 8;		}		else {			pdata += 4;			actual_length -= 4;		}				memcpy(riddata, pdata, actual_length);		riddata += actual_length;		pdata += actual_length;		length -= 64;		i++;	} while (length > 0);	return 0;}/* *	resreq: *		byte	type *		byte	sequence *		u16	reserved *		byte	data[12] *	total: 16 */static int zd1201_setconfig(struct zd1201 *zd, int rid, void *buf, int len, int wait){	int err;	unsigned char *request;	int reqlen;	char seq=0;	struct urb *urb;	unsigned int gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC;	len += 4;			/* first 4 are for header */	zd->rxdatas = 0;	zd->rxlen = 0;	for (seq=0; len > 0; seq++) {		request = kmalloc(16, gfp_mask);		if (!request)			return -ENOMEM;		urb = usb_alloc_urb(0, gfp_mask);		if (!urb) {			kfree(request);			return -ENOMEM;		}		memset(request, 0, 16);		reqlen = len>12 ? 12 : len;		request[0] = ZD1201_USB_RESREQ;		request[1] = seq;		request[2] = 0;		request[3] = 0;		if (request[1] == 0) {			/* add header */			*(__le16*)&request[4] = cpu_to_le16((len-2+1)/2);			*(__le16*)&request[6] = cpu_to_le16(rid);			memcpy(request+8, buf, reqlen-4);			buf += reqlen-4;		} else {			memcpy(request+4, buf, reqlen);			buf += reqlen;		}		len -= reqlen;		usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb,		    zd->endp_out2), request, 16, zd1201_usbfree, zd);		err = usb_submit_urb(urb, gfp_mask);		if (err)			goto err;	}	request = kmalloc(16, gfp_mask);	if (!request)		return -ENOMEM;	urb = usb_alloc_urb(0, gfp_mask);	if (!urb) {		kfree(request);		return -ENOMEM;	}	*((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ);	*((__le16*)&request[4]) = 	    cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT);	*((__le16*)&request[6]) = cpu_to_le16(rid);	*((__le16*)&request[8]) = cpu_to_le16(0);	*((__le16*)&request[10]) = cpu_to_le16(0);	usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),	     request, 16, zd1201_usbfree, zd);	err = usb_submit_urb(urb, gfp_mask);	if (err)		goto err;		if (wait) {		wait_event_interruptible(zd->rxdataq, zd->rxdatas);		if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) {			dev_dbg(&zd->usb->dev, "wrong or no RID received\n");		}	}	return 0;err:	kfree(request);	usb_free_urb(urb);	return err;}static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val){	int err;	__le16 zdval;	err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16));	if (err)		return err;	*val = le16_to_cpu(zdval);	return 0;}static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val){	__le16 zdval = cpu_to_le16(val);	return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1));}static int zd1201_drvr_start(struct zd1201 *zd){	int err, i;	short max;	__le16 zdmax;	unsigned char *buffer;		buffer = kmalloc(ZD1201_RXSIZE, GFP_KERNEL);	if (!buffer)		return -ENOMEM;	memset(buffer, 0, ZD1201_RXSIZE);	usb_fill_bulk_urb(zd->rx_urb, zd->usb, 	    usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,	    zd1201_usbrx, zd);	err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);	if (err)		goto err_buffer;		err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);	if (err)		goto err_urb;	err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax,	    sizeof(__le16));	if (err)		goto err_urb;	max = le16_to_cpu(zdmax);	for (i=0; i<max; i++) {		err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0);		if (err)			goto err_urb;	}	return 0;err_urb:	usb_kill_urb(zd->rx_urb);	return err;err_buffer:	kfree(buffer);	return err;}/*	Magic alert: The firmware doesn't seem to like the MAC state being *	toggled in promisc (aka monitor) mode. *	(It works a number of times, but will halt eventually) *	So we turn it of before disabling and on after enabling if needed. */static int zd1201_enable(struct zd1201 *zd){	int err;	if (zd->mac_enabled)		return 0;	err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0);	if (!err)		zd->mac_enabled = 1;	if (zd->monitor)		err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1);	return err;}static int zd1201_disable(struct zd1201 *zd){	int err;		if (!zd->mac_enabled)		return 0;	if (zd->monitor) {		err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);		if (err)			return err;	}	err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0);	if (!err)		zd->mac_enabled = 0;	return err;}static int zd1201_mac_reset(struct zd1201 *zd){	if (!zd->mac_enabled)		return 0;	zd1201_disable(zd);	return zd1201_enable(zd);}static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen){	int err, val;	char buf[IW_ESSID_MAX_SIZE+2];	err = zd1201_disable(zd);	if (err)		return err;	val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;	val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY;	err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val);	if (err)		return err;	*(__le16 *)buf = cpu_to_le16(essidlen);	memcpy(buf+2, essid, essidlen);	if (!zd->ap) {	/* Normal station */		err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,		    IW_ESSID_MAX_SIZE+2, 1);		if (err)			return err;	} else {	/* AP */		err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf,		    IW_ESSID_MAX_SIZE+2, 1);		if (err)			return err;	}	err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 	    zd->dev->dev_addr, zd->dev->addr_len, 1);	if (err)		return err;	err = zd1201_enable(zd);	if (err)		return err;	msleep(100);	return 0;}static int zd1201_net_open(struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	/* Start MAC with wildcard if no essid set */	if (!zd->mac_enabled)		zd1201_join(zd, zd->essid, zd->essidlen);	netif_start_queue(dev);	return 0;}static int zd1201_net_stop(struct net_device *dev){	netif_stop_queue(dev);		return 0;}/*	RFC 1042 encapsulates Ethernet frames in 802.11 frames	by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0	(0x00, 0x00, 0x00). Zd requires an additional padding, copy	of ethernet addresses, length of the standard RFC 1042 packet	and a command byte (which is nul for tx).		tx frame (from Wlan NG):	RFC 1042:		llc		0xAA 0xAA 0x03 (802.2 LLC)		snap		0x00 0x00 0x00 (Ethernet encapsulated)		type		2 bytes, Ethernet type field		payload		(minus eth header)	Zydas specific:		padding		1B if (skb->len+8+1)%64==0		Eth MAC addr	12 bytes, Ethernet MAC addresses		length		2 bytes, RFC 1042 packet length 				(llc+snap+type+payload)		zd		1 null byte, zd1201 packet type */static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	unsigned char *txbuf = zd->txdata;	int txbuflen, pad = 0, err;	struct urb *urb = zd->tx_urb;	if (!zd->mac_enabled || zd->monitor) {		zd->stats.tx_dropped++;		kfree_skb(skb);		return 0;	}	netif_stop_queue(dev);	txbuflen = skb->len + 8 + 1;	if (txbuflen%64 == 0) {		pad = 1;		txbuflen++;	}	txbuf[0] = 0xAA;	txbuf[1] = 0xAA;	txbuf[2] = 0x03;	txbuf[3] = 0x00;	/* rfc1042 */	txbuf[4] = 0x00;	txbuf[5] = 0x00;	memcpy(txbuf+6, skb->data+12, skb->len-12);	if (pad)		txbuf[skb->len-12+6]=0;	memcpy(txbuf+skb->len-12+6+pad, skb->data, 12);	*(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);	txbuf[txbuflen-1] = 0;	usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out),	    txbuf, txbuflen, zd1201_usbtx, zd);	err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);	if (err) {		zd->stats.tx_errors++;		netif_start_queue(dev);		return err;	}	zd->stats.tx_packets++;	zd->stats.tx_bytes += skb->len;	dev->trans_start = jiffies;	kfree_skb(skb);	return 0;}static void zd1201_tx_timeout(struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	if (!zd)		return;	dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",	    dev->name);	usb_unlink_urb(zd->tx_urb);	zd->stats.tx_errors++;	/* Restart the timeout to quiet the watchdog: */	dev->trans_start = jiffies;}static int zd1201_set_mac_address(struct net_device *dev, void *p){	struct sockaddr *addr = p;	struct zd1201 *zd = (struct zd1201 *)dev->priv;	int err;	if (!zd)		return -ENODEV;	err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR, 	    addr->sa_data, dev->addr_len, 1);	if (err)		return err;	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);	return zd1201_mac_reset(zd);}static struct net_device_stats *zd1201_get_stats(struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	return &zd->stats;}static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	return &zd->iwstats;}static void zd1201_set_multicast(struct net_device *dev){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	struct dev_mc_list *mc = dev->mc_list;	unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];	int i;	if (dev->mc_count > ZD1201_MAXMULTI)		return;	for (i=0; i<dev->mc_count; i++) {		memcpy(reqbuf+i*ETH_ALEN, mc->dmi_addr, ETH_ALEN);		mc = mc->next;	}	zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,	    dev->mc_count*ETH_ALEN, 0);	}static int zd1201_config_commit(struct net_device *dev,     struct iw_request_info *info, struct iw_point *data, char *essid){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	return zd1201_mac_reset(zd);}static int zd1201_get_name(struct net_device *dev,    struct iw_request_info *info, char *name, char *extra){	strcpy(name, "IEEE 802.11b");	return 0;}static int zd1201_set_freq(struct net_device *dev,    struct iw_request_info *info, struct iw_freq *freq, char *extra){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	short channel = 0;	int err;	if (freq->e == 0)		channel = freq->m;	else {		if (freq->m >= 2482)			channel = 14;		if (freq->m >= 2407)			channel = (freq->m-2407)/5;	}	err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);	if (err)		return err;	zd1201_mac_reset(zd);	return 0;}static int zd1201_get_freq(struct net_device *dev,    struct iw_request_info *info, struct iw_freq *freq, char *extra){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	short channel;	int err;	err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel);	if (err)		return err;	freq->e = 0;	freq->m = channel;	return 0;}static int zd1201_set_mode(struct net_device *dev,    struct iw_request_info *info, __u32 *mode, char *extra){	struct zd1201 *zd = (struct zd1201 *)dev->priv;	short porttype, monitor = 0;	unsigned char buffer[IW_ESSID_MAX_SIZE+2];	int err;	if (zd->ap) {		if (*mode != IW_MODE_MASTER)			return -EINVAL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -