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

📄 cdc-acm.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * acm.c  Version 0.21 * * Copyright (c) 1999 Armin Fuerst	<fuerst@in.tum.de> * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz> * Copyright (c) 1999 Johannes Erdfelt	<johannes@erdfelt.com> * Copyright (c) 2000 Vojtech Pavlik	<vojtech@suse.cz> * * USB Abstract Control Model driver for USB modems and ISDN adapters * * Sponsored by SuSE * * ChangeLog: *	v0.9  - thorough cleaning, URBification, almost a rewrite *	v0.10 - some more cleanups *	v0.11 - fixed flow control, read error doesn't stop reads *	v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced *	v0.13 - added termios, added hangup *	v0.14 - sized down struct acm *	v0.15 - fixed flow control again - characters could be lost *	v0.16 - added code for modems with swapped data and control interfaces *	v0.17 - added new style probing *	v0.18 - fixed new style probing for devices with more configurations *	v0.19 - fixed CLOCAL handling (thanks to Richard Shih-Ping Chan) *	v0.20 - switched to probing on interface (rather than device) class *	v0.21 - revert to probing on device for devices with multiple configs *//* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/kernel.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h>#include <linux/smp_lock.h>#undef DEBUG#include <linux/usb.h>#include <asm/byteorder.h>/* * Version Information */#define DRIVER_VERSION "v0.21"#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"/* * CMSPAR, some architectures can't have space and mark parity. */#ifndef CMSPAR#define CMSPAR			0#endif/* * Major and minor numbers. */#define ACM_TTY_MAJOR		166#define ACM_TTY_MINORS		32/* * Requests. */#define USB_RT_ACM		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)#define ACM_REQ_COMMAND		0x00#define ACM_REQ_RESPONSE	0x01#define ACM_REQ_SET_FEATURE	0x02#define ACM_REQ_GET_FEATURE	0x03#define ACM_REQ_CLEAR_FEATURE	0x04#define ACM_REQ_SET_LINE	0x20#define ACM_REQ_GET_LINE	0x21#define ACM_REQ_SET_CONTROL	0x22#define ACM_REQ_SEND_BREAK	0x23/* * IRQs. */#define ACM_IRQ_NETWORK		0x00#define ACM_IRQ_LINE_STATE	0x20/* * Output control lines. */#define ACM_CTRL_DTR		0x01#define ACM_CTRL_RTS		0x02/* * Input control lines and line errors. */#define ACM_CTRL_DCD		0x01#define ACM_CTRL_DSR		0x02#define ACM_CTRL_BRK		0x04#define ACM_CTRL_RI		0x08#define ACM_CTRL_FRAMING	0x10#define ACM_CTRL_PARITY		0x20#define ACM_CTRL_OVERRUN	0x40/* * Line speed and caracter encoding. */struct acm_line {	__u32 speed;	__u8 stopbits;	__u8 parity;	__u8 databits;} __attribute__ ((packed));/* * Internal driver structures. */struct acm {	struct usb_device *dev;				/* the coresponding usb device */	struct usb_interface *iface;			/* the interfaces - +0 control +1 data */	struct tty_struct *tty;				/* the coresponding tty */	struct urb *ctrlurb, *readurb, *writeurb;	/* urbs */	struct acm_line line;				/* line coding (bits, stop, parity) */	struct tq_struct tqueue;			/* task queue for line discipline waking up */	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */	unsigned int ctrlout;				/* output control lines (DTR, RTS) */	unsigned int writesize;				/* max packet size for the output bulk endpoint */	unsigned int used;				/* someone has this acm's device open */	unsigned int minor;				/* acm minor number */	unsigned char throttle;				/* throttled by tty layer */	unsigned char clocal;				/* termios CLOCAL */};static struct usb_driver acm_driver;static struct tty_driver acm_tty_driver;static struct acm *acm_table[ACM_TTY_MINORS];#define ACM_READY(acm)	(acm && acm->dev && acm->used)/* * Functions for ACM control messages. */static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len){	int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),		request, USB_RT_ACM, value, acm->iface[0].altsetting[0].bInterfaceNumber, buf, len, HZ * 5);	dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);	return retval < 0 ? retval : 0;}#define acm_set_control(acm, control)	acm_ctrl_msg(acm, ACM_REQ_SET_CONTROL, control, NULL, 0)#define acm_set_line(acm, line)		acm_ctrl_msg(acm, ACM_REQ_SET_LINE, 0, line, sizeof(struct acm_line))#define acm_send_break(acm, ms)		acm_ctrl_msg(acm, ACM_REQ_SEND_BREAK, ms, NULL, 0)/* * Interrupt handler for various ACM control events */static void acm_ctrl_irq(struct urb *urb){	struct acm *acm = urb->context;	struct usb_ctrlrequest *dr = urb->transfer_buffer;	unsigned char *data = (unsigned char *)(dr + 1);	int newctrl;	if (!ACM_READY(acm)) return;	if (urb->status < 0) {		dbg("nonzero ctrl irq status received: %d", urb->status);		return;	}	switch (dr->bRequest) {		case ACM_IRQ_NETWORK:			dbg("%s network", data[0] ? "connected to" : "disconnected from");			return;		case ACM_IRQ_LINE_STATE:			newctrl = le16_to_cpup((__u16 *) data);			if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {				dbg("calling hangup");				tty_hangup(acm->tty);			}			acm->ctrlin = newctrl;			dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",				acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',	acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',				acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',	acm->ctrlin & ACM_CTRL_RI  ? '+' : '-',				acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',	acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',				acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');			return;		default:			dbg("unknown control event received: request %d index %d len %d data0 %d data1 %d",				dr->bRequest, dr->wIndex, dr->wLength, data[0], data[1]);			return;	}}static void acm_read_bulk(struct urb *urb){	struct acm *acm = urb->context;	struct tty_struct *tty = acm->tty;	unsigned char *data = urb->transfer_buffer;	int i = 0;	if (!ACM_READY(acm)) return;	if (urb->status)		dbg("nonzero read bulk status received: %d", urb->status);	if (!urb->status & !acm->throttle)  {		for (i = 0; i < urb->actual_length && !acm->throttle; i++) {			/* if we insert more than TTY_FLIPBUF_SIZE characters,			 * we drop them. */			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {				tty_flip_buffer_push(tty);			}			tty_insert_flip_char(tty, data[i], 0);		}		tty_flip_buffer_push(tty);	}	if (acm->throttle) {		memmove(data, data + i, urb->actual_length - i);		urb->actual_length -= i;		return;	}	urb->actual_length = 0;	urb->dev = acm->dev;	if (usb_submit_urb(urb, GFP_KERNEL))		dbg("failed resubmitting read urb");}static void acm_write_bulk(struct urb *urb){	struct acm *acm = (struct acm *)urb->context;	if (!ACM_READY(acm)) return;	if (urb->status)		dbg("nonzero write bulk status received: %d", urb->status);	queue_task(&acm->tqueue, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static void acm_softint(void *private){	struct acm *acm = private;	struct tty_struct *tty = acm->tty;	if (!ACM_READY(acm)) return;	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);}/* * TTY handlers */static int acm_tty_open(struct tty_struct *tty, struct file *filp){	struct acm *acm = acm_table[minor(tty->device)];	if (!acm || !acm->dev) return -EINVAL;	tty->driver_data = acm;	acm->tty = tty;	MOD_INC_USE_COUNT;        lock_kernel();	if (acm->used++) {                unlock_kernel();                return 0;        }        unlock_kernel();	acm->ctrlurb->dev = acm->dev;	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL))		dbg("usb_submit_urb(ctrl irq) failed");	acm->readurb->dev = acm->dev;	if (usb_submit_urb(acm->readurb, GFP_KERNEL))		dbg("usb_submit_urb(read bulk) failed");	acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);	/* 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;	return 0;}static void acm_tty_close(struct tty_struct *tty, struct file *filp){	struct acm *acm = tty->driver_data;	if (!acm || !acm->used) return;	if (!--acm->used) {		if (acm->dev) {			acm_set_control(acm, acm->ctrlout = 0);			usb_unlink_urb(acm->ctrlurb);			usb_unlink_urb(acm->writeurb);			usb_unlink_urb(acm->readurb);		} else {			tty_unregister_devfs(&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);		}	}	MOD_DEC_USE_COUNT;}static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){	struct acm *acm = tty->driver_data;	if (!ACM_READY(acm)) return -EINVAL;	if (acm->writeurb->status == -EINPROGRESS) return 0;	if (!count) return 0;	count = (count > acm->writesize) ? acm->writesize : count;	if (from_user)		copy_from_user(acm->writeurb->transfer_buffer, buf, count);	else		memcpy(acm->writeurb->transfer_buffer, buf, count);	acm->writeurb->transfer_buffer_length = count;	acm->writeurb->dev = acm->dev;	if (usb_submit_urb(acm->writeurb, GFP_KERNEL))		dbg("usb_submit_urb(write bulk) failed");	return count;}static int acm_tty_write_room(struct tty_struct *tty)

⌨️ 快捷键说明

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