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

📄 cdc-acm.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	unsigned int newctrl;	if (!ACM_READY(acm))		return -EINVAL;	newctrl = acm->ctrlout;	set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);	clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);	newctrl = (newctrl & ~clear) | set;	if (acm->ctrlout == newctrl)		return 0;	return acm_set_control(acm, acm->ctrlout = newctrl);}static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return -EINVAL;	return -ENOIOCTLCMD;}static __u32 acm_tty_speed[] = {	0, 50, 75, 110, 134, 150, 200, 300, 600,	1200, 1800, 2400, 4800, 9600, 19200, 38400,	57600, 115200, 230400, 460800, 500000, 576000,	921600, 1000000, 1152000, 1500000, 2000000,	2500000, 3000000, 3500000, 4000000};static __u8 acm_tty_size[] = {	5, 6, 7, 8};static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old){	struct acm *acm = tty->driver_data;	struct termios *termios = tty->termios;	struct acm_line newline;	int newctrl = acm->ctrlout;	if (!ACM_READY(acm))		return;	newline.speed = cpu_to_le32p(acm_tty_speed +		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));	newline.stopbits = termios->c_cflag & CSTOPB ? 2 : 0;	newline.parity = termios->c_cflag & PARENB ?		(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;	newline.databits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];	acm->clocal = ((termios->c_cflag & CLOCAL) != 0);	if (!newline.speed) {		newline.speed = acm->line.speed;		newctrl &= ~ACM_CTRL_DTR;	} else  newctrl |=  ACM_CTRL_DTR;	if (newctrl != acm->ctrlout)		acm_set_control(acm, acm->ctrlout = newctrl);	if (memcmp(&acm->line, &newline, sizeof(struct acm_line))) {		memcpy(&acm->line, &newline, sizeof(struct acm_line));		dbg("set line: %d %d %d %d", newline.speed, newline.stopbits, newline.parity, newline.databits);		acm_set_line(acm, &acm->line);	}}/* * USB probe and disconnect routines. */static int acm_probe (struct usb_interface *intf,		      const struct usb_device_id *id){	struct union_desc *union_header = NULL;	char *buffer = intf->altsetting->extra;	int buflen = intf->altsetting->extralen;	struct usb_interface *control_interface;	struct usb_interface *data_interface;	struct usb_endpoint_descriptor *epctrl;	struct usb_endpoint_descriptor *epread;	struct usb_endpoint_descriptor *epwrite;	struct usb_device *usb_dev = interface_to_usbdev(intf);	struct acm *acm;	int minor;	int ctrlsize,readsize;	u8 *buf;	u8 ac_management_function = 0;	u8 call_management_function = 0;	int call_interface_num = -1;	int data_interface_num;	if (!buffer) {		err("Wierd descriptor references");		return -EINVAL;	}	while (buflen > 0) {		if (buffer [1] != USB_DT_CS_INTERFACE) {			err("skipping garbage");			goto next_desc;		}		switch (buffer [2]) {			case CDC_UNION_TYPE: /* we've found it */				if (union_header) {					err("More than one union descriptor, skipping ...");					goto next_desc;				}				union_header = (struct union_desc *)buffer;				break;			case CDC_COUNTRY_TYPE: /* maybe somehow export */				break; /* for now we ignore it */			case CDC_AC_MANAGEMENT_TYPE:				ac_management_function = buffer[3];				break;			case 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");				break;			}next_desc:		buflen -= buffer[0];		buffer += buffer[0];	}	if (!union_header) {		dev_dbg(&intf->dev,"No union descriptor, giving up\n");		return -ENODEV;	}	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\n");		return -ENODEV;	}		if (data_interface_num != call_interface_num)		dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");	if (usb_interface_claimed(data_interface)) { /* valid in this context */		dev_dbg(&intf->dev,"The data interface isn't available\n");		return -EBUSY;	}	/*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.\n");			t = control_interface;			control_interface = data_interface;			data_interface = t;		} else {			return -EINVAL;		}	}	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 ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {		/* descriptors are swapped */		struct usb_endpoint_descriptor *t;		dev_dbg(&intf->dev,"The data interface has switched endpoints\n");				t = epread;		epread = epwrite;		epwrite = t;	}	dbg("interfaces are valid");	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);	if (acm_table[minor]) {		err("no more free acm devices");		return -ENODEV;	}	if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {		dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n");		goto alloc_fail;	}	memset(acm, 0, sizeof(struct acm));	ctrlsize = epctrl->wMaxPacketSize;	readsize = epread->wMaxPacketSize;	acm->writesize = 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->bh.func = acm_rx_tasklet;	acm->bh.data = (unsigned long) acm;	INIT_WORK(&acm->work, acm_softint, acm);	spin_lock_init(&acm->throttle_lock);	acm->ready_for_write = 1;	buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);	if (!buf) {		dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");		goto alloc_fail2;	}	acm->ctrl_buffer = buf;	buf = usb_buffer_alloc(usb_dev, readsize, GFP_KERNEL, &acm->read_dma);	if (!buf) {		dev_dbg(&intf->dev, "out of memory (read buffer alloc)\n");		goto alloc_fail3;	}	acm->read_buffer = buf;	buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma);	if (!buf) {		dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");		goto alloc_fail4;	}	acm->write_buffer = buf;		acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);	if (!acm->ctrlurb) {		dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");		goto alloc_fail5;	}	acm->readurb = usb_alloc_urb(0, GFP_KERNEL);	if (!acm->readurb) {		dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n");		goto alloc_fail6;	}	acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);	if (!acm->writeurb) {		dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");		goto alloc_fail7;	}	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->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),			  acm->read_buffer, readsize, acm_read_bulk, acm);	acm->readurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;	acm->readurb->transfer_dma = acm->read_dma;	usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),			  acm->write_buffer, acm->writesize, acm_write_bulk, acm);	acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;	acm->writeurb->transfer_dma = acm->write_dma;	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);	acm_set_control(acm, acm->ctrlout);	acm->line.speed = cpu_to_le32(9600);	acm->line.databits = 8;	acm_set_line(acm, &acm->line);	usb_driver_claim_interface(&acm_driver, data_interface, acm);	tty_register_device(acm_tty_driver, minor, &intf->dev);	acm_table[minor] = acm;	usb_set_intfdata (intf, acm);	return 0;alloc_fail7:	usb_free_urb(acm->readurb);alloc_fail6:	usb_free_urb(acm->ctrlurb);alloc_fail5:	usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);alloc_fail4:	usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);alloc_fail3:	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);	if (!acm || !acm->dev) {		dbg("disconnect on nonexisting interface");		return;	}	down(&open_sem);	acm->dev = NULL;	usb_set_intfdata (intf, NULL);	usb_unlink_urb(acm->ctrlurb);	usb_unlink_urb(acm->readurb);	usb_unlink_urb(acm->writeurb);	flush_scheduled_work(); /* wait for acm_softint */	usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);	usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);	usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);	usb_driver_release_interface(&acm_driver, acm->data);	if (!acm->used) {		tty_unregister_device(acm_tty_driver, acm->minor);		acm_table[acm->minor] = NULL;		usb_free_urb(acm->ctrlurb);		usb_free_urb(acm->readurb);		usb_free_urb(acm->writeurb);		kfree(acm);		up(&open_sem);		return;	}	up(&open_sem);	if (acm->tty)		tty_hangup(acm->tty);}/* * USB driver structure. */static struct usb_device_id acm_ids[] = {	/* control interfaces with various AT-command sets */	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 1) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 2) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 3) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 4) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 5) },	{ USB_INTERFACE_INFO(USB_CLASS_COMM, 2, 6) },	/* NOTE:  COMM/2/0xff is likely MSFT RNDIS ... NOT a modem!! */	{ }};MODULE_DEVICE_TABLE (usb, acm_ids);static struct usb_driver acm_driver = {	.owner =	THIS_MODULE,	.name =		"cdc_acm",	.probe =	acm_probe,	.disconnect =	acm_disconnect,	.id_table =	acm_ids,};/* * TTY driver structures. */static 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->devfs_name = "usb/acm/",	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_NO_DEVFS,	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 + -