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

📄 cdc-acm.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 3 页
字号:
				  acm->readsize,				  acm_read_bulk, rcv);		rcv->urb->transfer_dma = buf->dma;		rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;		dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);		/* This shouldn't kill the driver as unsuccessful URBs are returned to the		   free-urbs-pool and resubmited ASAP */		if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {			list_add(&buf->list, &acm->spare_read_bufs);			spin_lock_irqsave(&acm->read_lock, flags);			list_add(&rcv->list, &acm->spare_read_urbs);			spin_unlock_irqrestore(&acm->read_lock, flags);			return;		}	}}/* data interface wrote those outgoing bytes */static void acm_write_bulk(struct urb *urb){	struct acm *acm = (struct acm *)urb->context;	dbg("Entering acm_write_bulk with status %d", urb->status);	acm_write_done(acm);	acm_write_start(acm);	if (ACM_READY(acm))		schedule_work(&acm->work);}static void acm_softint(struct work_struct *work){	struct acm *acm = container_of(work, struct acm, work);	dbg("Entering acm_softint.");		if (!ACM_READY(acm))		return;	tty_wakeup(acm->tty);}/* * TTY handlers */static int acm_tty_open(struct tty_struct *tty, struct file *filp){	struct acm *acm;	int rv = -EINVAL;	int i;	dbg("Entering acm_tty_open.");	mutex_lock(&open_mutex);	acm = acm_table[tty->index];	if (!acm || !acm->dev)		goto err_out;	else		rv = 0;	tty->driver_data = acm;	acm->tty = tty;	/* force low_latency on so that our tty_push actually forces the data through,	   otherwise it is scheduled, and with high data rates data can get lost. */	tty->low_latency = 1;	if (acm->used++) {		goto done;        }	acm->ctrlurb->dev = acm->dev;	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {		dbg("usb_submit_urb(ctrl irq) failed");		goto bail_out;	}	if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&	    (acm->ctrl_caps & USB_CDC_CAP_LINE))		goto full_bailout;	INIT_LIST_HEAD(&acm->spare_read_urbs);	INIT_LIST_HEAD(&acm->spare_read_bufs);	INIT_LIST_HEAD(&acm->filled_read_bufs);	for (i = 0; i < acm->rx_buflimit; i++) {		list_add(&(acm->ru[i].list), &acm->spare_read_urbs);	}	for (i = 0; i < acm->rx_buflimit; i++) {		list_add(&(acm->rb[i].list), &acm->spare_read_bufs);	}	acm->throttle = 0;	tasklet_schedule(&acm->urb_task);done:err_out:	mutex_unlock(&open_mutex);	return rv;full_bailout:	usb_kill_urb(acm->ctrlurb);bail_out:	acm->used--;	mutex_unlock(&open_mutex);	return -EIO;}static void acm_tty_unregister(struct acm *acm){	int i,nr;	nr = acm->rx_buflimit;	tty_unregister_device(acm_tty_driver, acm->minor);	usb_put_intf(acm->control);	acm_table[acm->minor] = NULL;	usb_free_urb(acm->ctrlurb);	usb_free_urb(acm->writeurb);	for (i = 0; i < nr; i++)		usb_free_urb(acm->ru[i].urb);	kfree(acm->country_codes);	kfree(acm);}static void acm_tty_close(struct tty_struct *tty, struct file *filp){	struct acm *acm = tty->driver_data;	int i,nr;	if (!acm || !acm->used)		return;	nr = acm->rx_buflimit;	mutex_lock(&open_mutex);	if (!--acm->used) {		if (acm->dev) {			acm_set_control(acm, acm->ctrlout = 0);			usb_kill_urb(acm->ctrlurb);			usb_kill_urb(acm->writeurb);			for (i = 0; i < nr; i++)				usb_kill_urb(acm->ru[i].urb);		} else			acm_tty_unregister(acm);	}	mutex_unlock(&open_mutex);}static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count){	struct acm *acm = tty->driver_data;	int stat;	unsigned long flags;	int wbn;	struct acm_wb *wb;	dbg("Entering acm_tty_write to write %d bytes,", count);	if (!ACM_READY(acm))		return -EINVAL;	if (!count)		return 0;	spin_lock_irqsave(&acm->write_lock, flags);	if ((wbn = acm_wb_alloc(acm)) < 0) {		spin_unlock_irqrestore(&acm->write_lock, flags);		acm_write_start(acm);		return 0;	}	wb = &acm->wb[wbn];	count = (count > acm->writesize) ? acm->writesize : count;	dbg("Get %d bytes...", count);	memcpy(wb->buf, buf, count);	wb->len = count;	spin_unlock_irqrestore(&acm->write_lock, flags);	if ((stat = acm_write_start(acm)) < 0)		return stat;	return count;}static int acm_tty_write_room(struct tty_struct *tty){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return -EINVAL;	/*	 * Do not let the line discipline to know that we have a reserve,	 * or it might get too enthusiastic.	 */	return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;}static int acm_tty_chars_in_buffer(struct tty_struct *tty){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return -EINVAL;	/*	 * This is inaccurate (overcounts), but it works.	 */	return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize;}static void acm_tty_throttle(struct tty_struct *tty){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return;	spin_lock_bh(&acm->throttle_lock);	acm->throttle = 1;	spin_unlock_bh(&acm->throttle_lock);}static void acm_tty_unthrottle(struct tty_struct *tty){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return;	spin_lock_bh(&acm->throttle_lock);	acm->throttle = 0;	spin_unlock_bh(&acm->throttle_lock);	tasklet_schedule(&acm->urb_task);}static void acm_tty_break_ctl(struct tty_struct *tty, int state){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return;	if (acm_send_break(acm, state ? 0xffff : 0))		dbg("send break failed");}static int acm_tty_tiocmget(struct tty_struct *tty, struct file *file){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm))		return -EINVAL;	return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |	       (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |	       (acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |	       (acm->ctrlin  & ACM_CTRL_RI  ? TIOCM_RI  : 0) |	       (acm->ctrlin  & ACM_CTRL_DCD ? TIOCM_CD  : 0) |	       TIOCM_CTS;}static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,			    unsigned int set, unsigned int clear){	struct acm *acm = tty->driver_data;	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 const __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 const __u8 acm_tty_size[] = {	5, 6, 7, 8};static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old){	struct acm *acm = tty->driver_data;	struct ktermios *termios = tty->termios;	struct usb_cdc_line_coding newline;	int newctrl = acm->ctrlout;	if (!ACM_READY(acm))		return;	newline.dwDTERate = cpu_to_le32p(acm_tty_speed +		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));	newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;	newline.bParityType = termios->c_cflag & PARENB ?		(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;	newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];	acm->clocal = ((termios->c_cflag & CLOCAL) != 0);	if (!newline.dwDTERate) {		newline.dwDTERate = acm->line.dwDTERate;		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 newline)) {		memcpy(&acm->line, &newline, sizeof newline);		dbg("set line: %d %d %d %d", le32_to_cpu(newline.dwDTERate),			newline.bCharFormat, newline.bParityType,			newline.bDataBits);		acm_set_line(acm, &acm->line);	}}/* * USB probe and disconnect routines. *//* Little helper: write buffers free */static void acm_write_buffers_free(struct acm *acm){	int i;	struct acm_wb *wb;	for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {		usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);	}}/* Little helper: write buffers allocate */static int acm_write_buffers_alloc(struct acm *acm){	int i;	struct acm_wb *wb;	for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {		wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,		    &wb->dmah);		if (!wb->buf) {			while (i != 0) {				--i;				--wb;				usb_buffer_free(acm->dev, acm->writesize,				    wb->buf, wb->dmah);			}			return -ENOMEM;		}	}	return 0;}static int acm_probe (struct usb_interface *intf,		      const struct usb_device_id *id){	struct usb_cdc_union_desc *union_header = NULL;	struct usb_cdc_country_functional_desc *cfd = 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;	unsigned long quirks;	int num_rx_buf;	int i;	/* normal quirks */	quirks = (unsigned long)id->driver_info;	num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR;	/* handle quirks deadly to normal probing*/	if (quirks == NO_UNION_NORMAL) {		data_interface = usb_ifnum_to_if(usb_dev, 1);		control_interface = usb_ifnum_to_if(usb_dev, 0);		goto skip_normal_probe;	}		/* normal probing*/	if (!buffer) {		err("Wierd descriptor references\n");		return -EINVAL;	}	if (!buflen) {		if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {			dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");			buflen = intf->cur_altsetting->endpoint->extralen;			buffer = intf->cur_altsetting->endpoint->extra;		} else {			err("Zero length descriptor references\n");			return -EINVAL;		}	}	while (buflen > 0) {		if (buffer [1] != USB_DT_CS_INTERFACE) {			err("skipping garbage\n");			goto next_desc;		}		switch (buffer [2]) {			case USB_CDC_UNION_TYPE: /* we've found it */				if (union_header) {					err("More than one union descriptor, skipping ...");

⌨️ 快捷键说明

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