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

📄 cdc-acm.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 3 页
字号:
					goto next_desc;				}				union_header = (struct usb_cdc_union_desc *)							buffer;				break;			case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/				cfd = (struct usb_cdc_country_functional_desc *)buffer;				break;			case USB_CDC_HEADER_TYPE: /* maybe check version */ 				break; /* for now we ignore it */ 			case USB_CDC_ACM_TYPE:				ac_management_function = buffer[3];				break;			case USB_CDC_CALL_MANAGEMENT_TYPE:				call_management_function = buffer[3];				call_interface_num = buffer[4];				if ((call_management_function & 3) != 3)					err("This device cannot do calls on its own. It is no modem.");				break;							default:				err("Ignoring extra header, type %d, length %d", buffer[2], buffer[0]);				break;			}next_desc:		buflen -= buffer[0];		buffer += buffer[0];	}	if (!union_header) {		if (call_interface_num > 0) {			dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");			data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));			control_interface = intf;		} else {			dev_dbg(&intf->dev,"No union descriptor, giving up");			return -ENODEV;		}	} else {		control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);		data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));		if (!control_interface || !data_interface) {			dev_dbg(&intf->dev,"no interfaces");			return -ENODEV;		}	}		if (data_interface_num != call_interface_num)		dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");skip_normal_probe:	/*workaround for switched interfaces */	if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {		if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {			struct usb_interface *t;			dev_dbg(&intf->dev,"Your device has switched interfaces.");			t = control_interface;			control_interface = data_interface;			data_interface = t;		} else {			return -EINVAL;		}	}		/* Accept probe requests only for the control interface */	if (intf != control_interface)		return -ENODEV;		if (usb_interface_claimed(data_interface)) { /* valid in this context */		dev_dbg(&intf->dev,"The data interface isn't available");		return -EBUSY;	}	if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)		return -EINVAL;	epctrl = &control_interface->cur_altsetting->endpoint[0].desc;	epread = &data_interface->cur_altsetting->endpoint[0].desc;	epwrite = &data_interface->cur_altsetting->endpoint[1].desc;	/* workaround for switched endpoints */	if (!usb_endpoint_dir_in(epread)) {		/* descriptors are swapped */		struct usb_endpoint_descriptor *t;		dev_dbg(&intf->dev,"The data interface has switched endpoints");				t = epread;		epread = epwrite;		epwrite = t;	}	dbg("interfaces are valid");	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);	if (minor == ACM_TTY_MINORS) {		err("no more free acm devices");		return -ENODEV;	}	if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {		dev_dbg(&intf->dev, "out of memory (acm kzalloc)");		goto alloc_fail;	}	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);	readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);	acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);	acm->control = control_interface;	acm->data = data_interface;	acm->minor = minor;	acm->dev = usb_dev;	acm->ctrl_caps = ac_management_function;	acm->ctrlsize = ctrlsize;	acm->readsize = readsize;	acm->rx_buflimit = num_rx_buf;	acm->urb_task.func = acm_rx_tasklet;	acm->urb_task.data = (unsigned long) acm;	INIT_WORK(&acm->work, acm_softint);	spin_lock_init(&acm->throttle_lock);	spin_lock_init(&acm->write_lock);	spin_lock_init(&acm->read_lock);	acm->write_ready = 1;	acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);	if (!buf) {		dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");		goto alloc_fail2;	}	acm->ctrl_buffer = buf;	if (acm_write_buffers_alloc(acm) < 0) {		dev_dbg(&intf->dev, "out of memory (write buffer alloc)");		goto alloc_fail4;	}	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);	if (!acm->ctrlurb) {		dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");		goto alloc_fail5;	}	for (i = 0; i < num_rx_buf; i++) {		struct acm_ru *rcv = &(acm->ru[i]);		if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {			dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");			goto alloc_fail7;		}		rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;		rcv->instance = acm;	}	for (i = 0; i < num_rx_buf; i++) {		struct acm_rb *buf = &(acm->rb[i]);		if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {			dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");			goto alloc_fail7;		}	}	acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);	if (!acm->writeurb) {		dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");		goto alloc_fail7;	}	usb_set_intfdata (intf, acm);	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);	if (i < 0)		goto alloc_fail8;	if (cfd) { /* export the country data */		acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL);		if (!acm->country_codes)			goto skip_countries;		acm->country_code_size = cfd->bLength - 4;		memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);		acm->country_rel_date = cfd->iCountryCodeRelDate;		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);		if (i < 0) {			kfree(acm->country_codes);			goto skip_countries;		}		i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);		if (i < 0) {			kfree(acm->country_codes);			goto skip_countries;		}	}skip_countries:	usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),			 acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);	acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;	acm->ctrlurb->transfer_dma = acm->ctrl_dma;	usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),			  NULL, acm->writesize, acm_write_bulk, acm);	acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);	acm_set_control(acm, acm->ctrlout);	acm->line.dwDTERate = cpu_to_le32(9600);	acm->line.bDataBits = 8;	acm_set_line(acm, &acm->line);	usb_driver_claim_interface(&acm_driver, data_interface, acm);	usb_get_intf(control_interface);	tty_register_device(acm_tty_driver, minor, &control_interface->dev);	acm_table[minor] = acm;	return 0;alloc_fail8:	usb_free_urb(acm->writeurb);alloc_fail7:	for (i = 0; i < num_rx_buf; i++)		usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);	for (i = 0; i < num_rx_buf; i++)		usb_free_urb(acm->ru[i].urb);	usb_free_urb(acm->ctrlurb);alloc_fail5:	acm_write_buffers_free(acm);alloc_fail4:	usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);alloc_fail2:	kfree(acm);alloc_fail:	return -ENOMEM;}static void acm_disconnect(struct usb_interface *intf){	struct acm *acm = usb_get_intfdata(intf);	struct usb_device *usb_dev = interface_to_usbdev(intf);	int i;	if (!acm || !acm->dev) {		dbg("disconnect on nonexisting interface");		return;	}	mutex_lock(&open_mutex);	if (!usb_get_intfdata(intf)) {		mutex_unlock(&open_mutex);		return;	}	if (acm->country_codes){		device_remove_file(&acm->control->dev,				&dev_attr_wCountryCodes);		device_remove_file(&acm->control->dev,				&dev_attr_iCountryCodeRelDate);	}	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);	acm->dev = NULL;	usb_set_intfdata(acm->control, NULL);	usb_set_intfdata(acm->data, NULL);	tasklet_disable(&acm->urb_task);	usb_kill_urb(acm->ctrlurb);	usb_kill_urb(acm->writeurb);	for (i = 0; i < acm->rx_buflimit; i++)		usb_kill_urb(acm->ru[i].urb);	INIT_LIST_HEAD(&acm->filled_read_bufs);	INIT_LIST_HEAD(&acm->spare_read_bufs);	tasklet_enable(&acm->urb_task);	flush_scheduled_work(); /* wait for acm_softint */	acm_write_buffers_free(acm);	usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);	for (i = 0; i < acm->rx_buflimit; i++)		usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);	usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf);	if (!acm->used) {		acm_tty_unregister(acm);		mutex_unlock(&open_mutex);		return;	}	mutex_unlock(&open_mutex);	if (acm->tty)		tty_hangup(acm->tty);}/* * USB driver structure. */static struct usb_device_id acm_ids[] = {	/* quirky and broken devices */	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */	},	{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */	},	{ USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */	},	{ USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */	.driver_info = SINGLE_RX_URB, /* firmware bug */	},	{ USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */	.driver_info = SINGLE_RX_URB, /* firmware bug */	},	{ USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */	},	/* control interfaces with various AT-command sets */	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_V25TER) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_PCCA101) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_GSM) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_3G	) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,		USB_CDC_ACM_PROTO_AT_CDMA) },	/* NOTE:  COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */	{ }};MODULE_DEVICE_TABLE (usb, acm_ids);static struct usb_driver acm_driver = {	.name =		"cdc_acm",	.probe =	acm_probe,	.disconnect =	acm_disconnect,	.id_table =	acm_ids,};/* * TTY driver structures. */static const struct tty_operations acm_ops = {	.open =			acm_tty_open,	.close =		acm_tty_close,	.write =		acm_tty_write,	.write_room =		acm_tty_write_room,	.ioctl =		acm_tty_ioctl,	.throttle =		acm_tty_throttle,	.unthrottle =		acm_tty_unthrottle,	.chars_in_buffer =	acm_tty_chars_in_buffer,	.break_ctl =		acm_tty_break_ctl,	.set_termios =		acm_tty_set_termios,	.tiocmget =		acm_tty_tiocmget,	.tiocmset =		acm_tty_tiocmset,};/* * Init / exit. */static int __init acm_init(void){	int retval;	acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);	if (!acm_tty_driver)		return -ENOMEM;	acm_tty_driver->owner = THIS_MODULE,	acm_tty_driver->driver_name = "acm",	acm_tty_driver->name = "ttyACM",	acm_tty_driver->major = ACM_TTY_MAJOR,	acm_tty_driver->minor_start = 0,	acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,	acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,	acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;	acm_tty_driver->init_termios = tty_std_termios;	acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;	tty_set_operations(acm_tty_driver, &acm_ops);	retval = tty_register_driver(acm_tty_driver);	if (retval) {		put_tty_driver(acm_tty_driver);		return retval;	}	retval = usb_register(&acm_driver);	if (retval) {		tty_unregister_driver(acm_tty_driver);		put_tty_driver(acm_tty_driver);		return retval;	}	info(DRIVER_VERSION ":" DRIVER_DESC);	return 0;}static void __exit acm_exit(void){	usb_deregister(&acm_driver);	tty_unregister_driver(acm_tty_driver);	put_tty_driver(acm_tty_driver);}module_init(acm_init);module_exit(acm_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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