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

📄 zd_usb.c

📁 zd1211无线网卡驱动源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
int zd_usb_enable_rx(struct zd_usb *usb){	int i, r;	struct zd_usb_rx *rx = &usb->rx;	struct urb **urbs;	dev_dbg_f(zd_usb_dev(usb), "\n");	r = -ENOMEM;	urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);	if (!urbs)		goto error;	for (i = 0; i < URBS_COUNT; i++) {		urbs[i] = alloc_urb(usb);		if (!urbs[i])			goto error;	}	ZD_ASSERT(!irqs_disabled());	spin_lock_irq(&rx->lock);	if (rx->urbs) {		spin_unlock_irq(&rx->lock);		r = 0;		goto error;	}	rx->urbs = urbs;	rx->urbs_count = URBS_COUNT;	spin_unlock_irq(&rx->lock);	for (i = 0; i < URBS_COUNT; i++) {		r = usb_submit_urb(urbs[i], GFP_NOFS);		if (r)			goto error_submit;	}	return 0;error_submit:	for (i = 0; i < URBS_COUNT; i++) {		usb_kill_urb(urbs[i]);	}	spin_lock_irq(&rx->lock);	rx->urbs = NULL;	rx->urbs_count = 0;	spin_unlock_irq(&rx->lock);error:	if (urbs) {		for (i = 0; i < URBS_COUNT; i++)			free_urb(urbs[i]);	}	return r;}void zd_usb_disable_rx(struct zd_usb *usb){	int i;	unsigned long flags;	struct urb **urbs;	unsigned int count;	struct zd_usb_rx *rx = &usb->rx;	spin_lock_irqsave(&rx->lock, flags);	urbs = rx->urbs;	count = rx->urbs_count;	spin_unlock_irqrestore(&rx->lock, flags);	if (!urbs)		return;	for (i = 0; i < count; i++) {		usb_kill_urb(urbs[i]);		free_urb(urbs[i]);	}	kfree(urbs);	spin_lock_irqsave(&rx->lock, flags);	rx->urbs = NULL;	rx->urbs_count = 0;	spin_unlock_irqrestore(&rx->lock, flags);}static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs){	int r;	switch (urb->status) {	case 0:		break;	case -ESHUTDOWN:	case -EINVAL:	case -ENODEV:	case -ENOENT:	case -ECONNRESET:	case -EPIPE:		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);		break;	default:		dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);		goto resubmit;	}free_urb:	usb_buffer_free(urb->dev, urb->transfer_buffer_length,		        urb->transfer_buffer, urb->transfer_dma);	usb_free_urb(urb);	return;resubmit:	r = usb_submit_urb(urb, GFP_ATOMIC);	if (r) {		dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);		goto free_urb;	}}/* Puts the frame on the USB endpoint. It doesn't wait for * completion. The frame must contain the control set. */int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length){	int r;	struct usb_device *udev = zd_usb_to_usbdev(usb);	struct urb *urb;	void *buffer;	urb = usb_alloc_urb(0, GFP_ATOMIC);	if (!urb) {		r = -ENOMEM;		goto out;	}	buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,		                  &urb->transfer_dma);	if (!buffer) {		r = -ENOMEM;		goto error_free_urb;	}	memcpy(buffer, frame, length);	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),		          buffer, length, tx_urb_complete, NULL);	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;	r = usb_submit_urb(urb, GFP_ATOMIC);	if (r)		goto error;	return 0;error:	usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,		        urb->transfer_dma);error_free_urb:	usb_free_urb(urb);out:	return r;}static inline void init_usb_interrupt(struct zd_usb *usb){	struct zd_usb_interrupt *intr = &usb->intr;	spin_lock_init(&intr->lock);	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));	init_completion(&intr->read_regs.completion);	intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));}static inline void init_usb_rx(struct zd_usb *usb){	struct zd_usb_rx *rx = &usb->rx;	spin_lock_init(&rx->lock);	if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {		rx->usb_packet_size = 512;	} else {		rx->usb_packet_size = 64;	}	ZD_ASSERT(rx->fragment_length == 0);}static inline void init_usb_tx(struct zd_usb *usb){	/* FIXME: at this point we will allocate a fixed number of urb's for	 * use in a cyclic scheme */}void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,	         struct usb_interface *intf){	memset(usb, 0, sizeof(*usb));	usb->intf = usb_get_intf(intf);	usb_set_intfdata(usb->intf, netdev);	init_usb_interrupt(usb);	init_usb_tx(usb);	init_usb_rx(usb);}int zd_usb_init_hw(struct zd_usb *usb){	int r;	struct zd_chip *chip = zd_usb_to_chip(usb);	ZD_ASSERT(mutex_is_locked(&chip->mutex));	r = zd_ioread16_locked(chip, &usb->fw_base_offset,		        USB_REG((u16)FW_BASE_ADDR_OFFSET));	if (r)		return r;	dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",		 usb->fw_base_offset);	return 0;}void zd_usb_clear(struct zd_usb *usb){	usb_set_intfdata(usb->intf, NULL);	usb_put_intf(usb->intf);	memset(usb, 0, sizeof(*usb));	/* FIXME: usb_interrupt, usb_tx, usb_rx? */}static const char *speed(enum usb_device_speed speed){	switch (speed) {	case USB_SPEED_LOW:		return "low";	case USB_SPEED_FULL:		return "full";	case USB_SPEED_HIGH:		return "high";	default:		return "unknown speed";	}}static int scnprint_id(struct usb_device *udev, char *buffer, size_t size){	return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",		le16_to_cpu(udev->descriptor.idVendor),		le16_to_cpu(udev->descriptor.idProduct),		get_bcdDevice(udev),		speed(udev->speed));}int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size){	struct usb_device *udev = interface_to_usbdev(usb->intf);	return scnprint_id(udev, buffer, size);}#ifdef DEBUGstatic void print_id(struct usb_device *udev){	char buffer[40];	scnprint_id(udev, buffer, sizeof(buffer));	buffer[sizeof(buffer)-1] = 0;	dev_dbg_f(&udev->dev, "%s\n", buffer);}#else#define print_id(udev) do { } while (0)#endifstatic int probe(struct usb_interface *intf, const struct usb_device_id *id){	int r;	struct usb_device *udev = interface_to_usbdev(intf);	struct net_device *netdev = NULL;	print_id(udev);	switch (udev->speed) {	case USB_SPEED_LOW:	case USB_SPEED_FULL:	case USB_SPEED_HIGH:		break;	default:		dev_dbg_f(&intf->dev, "Unknown USB speed\n");		r = -ENODEV;		goto error;	}	netdev = zd_netdev_alloc(intf);	if (netdev == NULL) {		r = -ENOMEM;		goto error;	}	r = upload_firmware(udev, id->driver_info);	if (r) {		dev_err(&intf->dev,		       "couldn't load firmware. Error number %d\n", r);		goto error;	}	r = usb_reset_configuration(udev);	if (r) {		dev_dbg_f(&intf->dev,			"couldn't reset configuration. Error number %d\n", r);		goto error;	}	/* At this point the interrupt endpoint is not generally enabled. We	 * save the USB bandwidth until the network device is opened. But	 * notify that the initialization of the MAC will require the	 * interrupts to be temporary enabled.	 */	r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);	if (r) {		dev_dbg_f(&intf->dev,		         "couldn't initialize mac. Error number %d\n", r);		goto error;	}	r = register_netdev(netdev);	if (r) {		dev_dbg_f(&intf->dev,			 "couldn't register netdev. Error number %d\n", r);		goto error;	}	dev_dbg_f(&intf->dev, "successful\n");	dev_info(&intf->dev,"%s\n", netdev->name);	return 0;error:	usb_reset_device(interface_to_usbdev(intf));	zd_netdev_free(netdev);	return r;}static void disconnect(struct usb_interface *intf){	struct net_device *netdev = zd_intf_to_netdev(intf);	struct zd_mac *mac = zd_netdev_mac(netdev);	struct zd_usb *usb = &mac->chip.usb;	dev_dbg_f(zd_usb_dev(usb), "\n");	zd_netdev_disconnect(netdev);	/* Just in case something has gone wrong! */	zd_usb_disable_rx(usb);	zd_usb_disable_int(usb);	/* If the disconnect has been caused by a removal of the	 * driver module, the reset allows reloading of the driver. If the	 * reset will not be executed here, the upload of the firmware in the	 * probe function caused by the reloading of the driver will fail.	 */	usb_reset_device(interface_to_usbdev(intf));	/* If somebody still waits on this lock now, this is an error. */	zd_netdev_free(netdev);	dev_dbg(&intf->dev, "disconnected\n");}static struct usb_driver driver = {	.name		= "zd1211rw",	.id_table	= usb_ids,	.probe		= probe,	.disconnect	= disconnect,};static int __init usb_init(void){	int r;	pr_debug("usb_init()\n");	r = usb_register(&driver);	if (r) {		printk(KERN_ERR "usb_register() failed. Error number %d\n", r);		return r;	}	pr_debug("zd1211rw initialized\n");	return 0;}static void __exit usb_exit(void){	pr_debug("usb_exit()\n");	usb_deregister(&driver);}module_init(usb_init);module_exit(usb_exit);static int usb_int_regs_length(unsigned int count){	return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);}static void prepare_read_regs_int(struct zd_usb *usb){	struct zd_usb_interrupt *intr = &usb->intr;	spin_lock(&intr->lock);	intr->read_regs_enabled = 1;	INIT_COMPLETION(intr->read_regs.completion);	spin_unlock(&intr->lock);}static int get_results(struct zd_usb *usb, u16 *values,	               struct usb_req_read_regs *req, unsigned int count){	int r;	int i;	struct zd_usb_interrupt *intr = &usb->intr;	struct read_regs_int *rr = &intr->read_regs;	struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;	spin_lock(&intr->lock);	r = -EIO;	/* The created block size seems to be larger than expected.	 * However results appear to be correct.	 */	if (rr->length < usb_int_regs_length(count)) {		dev_dbg_f(zd_usb_dev(usb),			 "error: actual length %d less than expected %d\n",			 rr->length, usb_int_regs_length(count));		goto error_unlock;	}	if (rr->length > sizeof(rr->buffer)) {		dev_dbg_f(zd_usb_dev(usb),			 "error: actual length %d exceeds buffer size %zu\n",			 rr->length, sizeof(rr->buffer));		goto error_unlock;	}	for (i = 0; i < count; i++) {		struct reg_data *rd = &regs->regs[i];		if (rd->addr != req->addr[i]) {			dev_dbg_f(zd_usb_dev(usb),				 "rd[%d] addr %#06hx expected %#06hx\n", i,				 le16_to_cpu(rd->addr),				 le16_to_cpu(req->addr[i]));			goto error_unlock;		}		values[i] = le16_to_cpu(rd->value);	}	r = 0;error_unlock:	spin_unlock(&intr->lock);	return r;}int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,	             const zd_addr_t *addresses, unsigned int count){	int r;	int i, req_len, actual_req_len;	struct usb_device *udev;	struct usb_req_read_regs *req = NULL;	unsigned long timeout;	if (count < 1) {		dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");		return -EINVAL;	}	if (count > USB_MAX_IOREAD16_COUNT) {		dev_dbg_f(zd_usb_dev(usb),			 "error: count %u exceeds possible max %u\n",			 count, USB_MAX_IOREAD16_COUNT);		return -EINVAL;	}	if (in_atomic()) {		dev_dbg_f(zd_usb_dev(usb),			 "error: io in atomic context not supported\n");		return -EWOULDBLOCK;	}	if (!usb_int_enabled(usb)) {		 dev_dbg_f(zd_usb_dev(usb),			  "error: usb interrupt not enabled\n");		return -EWOULDBLOCK;	}	req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);	req = kmalloc(req_len, GFP_NOFS);	if (!req)		return -ENOMEM;	req->id = cpu_to_le16(USB_REQ_READ_REGS);	for (i = 0; i < count; i++)		req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));	udev = zd_usb_to_usbdev(usb);	prepare_read_regs_int(usb);	r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),		         req, req_len, &actual_req_len, 1000 /* ms */);	if (r) {		dev_dbg_f(zd_usb_dev(usb),			"error in usb_bulk_msg(). Error number %d\n", r);		goto error;	}	if (req_len != actual_req_len) {		dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"			" req_len %d != actual_req_len %d\n",			req_len, actual_req_len);		r = -EIO;		goto error;	}	timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,	                                      msecs_to_jiffies(1000));	if (!timeout) {		disable_read_regs_int(usb);		dev_dbg_f(zd_usb_dev(usb), "read timed out\n");		r = -ETIMEDOUT;		goto error;	}	r = get_results(usb, values, req, count);error:	kfree(req);	return r;}int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,	              unsigned int count){	int r;	struct usb_device *udev;	struct usb_req_write_regs *req = NULL;	int i, req_len, actual_req_len;	if (count == 0)		return 0;	if (count > USB_MAX_IOWRITE16_COUNT) {		dev_dbg_f(zd_usb_dev(usb),			"error: count %u exceeds possible max %u\n",			count, USB_MAX_IOWRITE16_COUNT);		return -EINVAL;	}	if (in_atomic()) {		dev_dbg_f(zd_usb_dev(usb),			"error: io in atomic context not supported\n");		return -EWOULDBLOCK;	}	req_len = sizeof(struct usb_req_write_regs) +		  count * sizeof(struct reg_data);	req = kmalloc(req_len, GFP_NOFS);	if (!req)		return -ENOMEM;	req->id = cpu_to_le16(USB_REQ_WRITE_REGS);	for (i = 0; i < count; i++) {		struct reg_data *rw  = &req->reg_writes[i];		rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));		rw->value = cpu_to_le16(ioreqs[i].value);	}	udev = zd_usb_to_usbdev(usb);	r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),		         req, req_len, &actual_req_len, 1000 /* ms */);	if (r) {		dev_dbg_f(zd_usb_dev(usb),			"error in usb_bulk_msg(). Error number %d\n", r);		goto error;	}	if (req_len != actual_req_len) {		dev_dbg_f(zd_usb_dev(usb),			"error in usb_bulk_msg()"			" req_len %d != actual_req_len %d\n",			req_len, actual_req_len);		r = -EIO;		goto error;	}	/* FALL-THROUGH with r == 0 */error:	kfree(req);	return r;}int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits){	int r;	struct usb_device *udev;	struct usb_req_rfwrite *req = NULL;	int i, req_len, actual_req_len;	u16 bit_value_template;	if (in_atomic()) {		dev_dbg_f(zd_usb_dev(usb),			"error: io in atomic context not supported\n");		return -EWOULDBLOCK;	}	if (bits < USB_MIN_RFWRITE_BIT_COUNT) {		dev_dbg_f(zd_usb_dev(usb),			"error: bits %d are smaller than"			" USB_MIN_RFWRITE_BIT_COUNT %d\n",			bits, USB_MIN_RFWRITE_BIT_COUNT);		return -EINVAL;	}	if (bits > USB_MAX_RFWRITE_BIT_COUNT) {		dev_dbg_f(zd_usb_dev(usb),			"error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",			bits, USB_MAX_RFWRITE_BIT_COUNT);		return -EINVAL;	}#ifdef DEBUG	if (value & (~0UL << bits)) {		dev_dbg_f(zd_usb_dev(usb),			"error: value %#09x has bits >= %d set\n",			value, bits);		return -EINVAL;	}#endif /* DEBUG */	dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);	r = zd_usb_ioread16(usb, &bit_value_template, CR203);	if (r) {		dev_dbg_f(zd_usb_dev(usb),			"error %d: Couldn't read CR203\n", r);		goto out;	}	bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);	req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);	req = kmalloc(req_len, GFP_NOFS);	if (!req)		return -ENOMEM;	req->id = cpu_to_le16(USB_REQ_WRITE_RF);	/* 1: 3683a, but not used in ZYDAS driver */	req->value = cpu_to_le16(2);	req->bits = cpu_to_le16(bits);	for (i = 0; i < bits; i++) {		u16 bv = bit_value_template;		if (value & (1 << (bits-1-i)))			bv |= RF_DATA;		req->bit_values[i] = cpu_to_le16(bv);	}	udev = zd_usb_to_usbdev(usb);	r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),		         req, req_len, &actual_req_len, 1000 /* ms */);	if (r) {		dev_dbg_f(zd_usb_dev(usb),			"error in usb_bulk_msg(). Error number %d\n", r);		goto out;	}	if (req_len != actual_req_len) {		dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"			" req_len %d != actual_req_len %d\n",			req_len, actual_req_len);		r = -EIO;		goto out;	}	/* FALL-THROUGH with r == 0 */out:	kfree(req);	return r;}

⌨️ 快捷键说明

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