亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? cdc-acm.c

?? USB Abstract Control Model driver for USB modems and ISDN adapters(for Linux)
?? C
?? 第 1 頁 / 共 2 頁
字號:
/*
 * cdc-acm.c
 *
 * 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>
 * Copyright (c) 2004 Oliver Neukum	<oliver@neukum.name>
 *
 * 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
 *	v0.22 - probe only the control interface. if usbcore doesn't choose the
 *		config we want, sysadmin changes bConfigurationValue in sysfs.
 *	v0.23 - use softirq for rx processing, as needed by tty layer
 *	v0.24 - change probe method to evaluate CDC union descriptor
 */

/*
 * 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
 */

#undef DEBUG

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>

#include "cdc-acm.h"

/*
 * Version Information
 */
#define DRIVER_VERSION "v0.23"
#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"

static struct usb_driver acm_driver;
static struct tty_driver *acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS];

static DECLARE_MUTEX(open_sem);

#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->control->altsetting[0].desc.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;
}

/* devices aren't required to support these requests.
 * the cdc acm descriptor tells whether they do...
 */
#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 handlers for various ACM device responses
 */

/* control interface reports status changes with "interrupt" transfers */
static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
{
	struct acm *acm = urb->context;
	struct usb_ctrlrequest *dr = urb->transfer_buffer;
	unsigned char *data;
	int newctrl;
	int status;

	switch (urb->status) {
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
		return;
	default:
		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
		goto exit;
	}

	if (!ACM_READY(acm))
		goto exit;

	data = (unsigned char *)(dr + 1);
	switch (dr->bRequest) {

		case ACM_IRQ_NETWORK:

			dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
			break;

		case ACM_IRQ_LINE_STATE:

			newctrl = le16_to_cpu(get_unaligned((__le16 *) 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 ? '+' : '-');

			break;

		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]);
			break;
	}
exit:
	status = usb_submit_urb (urb, GFP_ATOMIC);
	if (status)
		err ("%s - usb_submit_urb failed with result %d",
		     __FUNCTION__, status);
}

/* data interface returns incoming bytes, or we got unthrottled */
static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
{
	struct acm *acm = urb->context;
	dbg("Entering acm_read_bulk with status %d\n", urb->status);

	if (!ACM_READY(acm))
		return;

	if (urb->status)
		dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);

	/* calling tty_flip_buffer_push() in_irq() isn't allowed */
	tasklet_schedule(&acm->bh);
}

static void acm_rx_tasklet(unsigned long _acm)
{
	struct acm *acm = (void *)_acm;
	struct urb *urb = acm->readurb;
	struct tty_struct *tty = acm->tty;
	unsigned char *data = urb->transfer_buffer;
	int i = 0;
	dbg("Entering acm_rx_tasklet");

	if (urb->actual_length > 0 && !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);
		}
		dbg("Handed %d bytes to tty layer", i+1);
		tty_flip_buffer_push(tty);
	}

	spin_lock(&acm->throttle_lock);
	if (acm->throttle) {
		dbg("Throtteling noticed");
		memmove(data, data + i, urb->actual_length - i);
		urb->actual_length -= i;
		acm->resubmit_to_unthrottle = 1;
		spin_unlock(&acm->throttle_lock);
		return;
	}
	spin_unlock(&acm->throttle_lock);

	urb->actual_length = 0;
	urb->dev = acm->dev;

	i = usb_submit_urb(urb, GFP_ATOMIC);
	if (i)
		dev_dbg(&acm->data->dev, "bulk rx resubmit %d\n", i);
}

/* data interface wrote those outgoing bytes */
static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
	struct acm *acm = (struct acm *)urb->context;
	dbg("Entering acm_write_bulk with status %d\n", urb->status);

	if (!ACM_READY(acm))
		goto out;

	if (urb->status)
		dbg("nonzero write bulk status received: %d", urb->status);

	schedule_work(&acm->work);
out:
	acm->ready_for_write = 1;
}

static void acm_softint(void *private)
{
	struct acm *acm = private;
	dbg("Entering acm_softint.\n");
	
	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;
	dbg("Entering acm_tty_open.\n");
	
	down(&open_sem);

	acm = acm_table[tty->index];
	if (!acm || !acm->dev)
		goto err_out;
	else
		rv = 0;

	tty->driver_data = acm;
	acm->tty = tty;



	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;
	}

	acm->readurb->dev = acm->dev;
	if (usb_submit_urb(acm->readurb, GFP_KERNEL)) {
		dbg("usb_submit_urb(read bulk) failed");
		goto bail_out_and_unlink;
	}

	if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
		goto full_bailout;

	/* 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;

done:
err_out:
	up(&open_sem);
	return rv;

full_bailout:
	usb_kill_urb(acm->readurb);
bail_out_and_unlink:
	usb_kill_urb(acm->ctrlurb);
bail_out:
	acm->used--;
	up(&open_sem);
	return -EIO;
}

static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
	struct acm *acm = tty->driver_data;

	if (!acm || !acm->used)
		return;

	down(&open_sem);
	if (!--acm->used) {
		if (acm->dev) {
			acm_set_control(acm, acm->ctrlout = 0);
			usb_kill_urb(acm->ctrlurb);
			usb_kill_urb(acm->writeurb);
			usb_kill_urb(acm->readurb);
		} else {
			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);
}

static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
	struct acm *acm = tty->driver_data;
	int stat;
	dbg("Entering acm_tty_write to write %d bytes,\n", count);

	if (!ACM_READY(acm))
		return -EINVAL;
	if (!acm->ready_for_write)
		return 0;
	if (!count)
		return 0;

	count = (count > acm->writesize) ? acm->writesize : count;

	dbg("Get %d bytes...", count);
	memcpy(acm->write_buffer, buf, count);
	dbg("  Successfully copied.\n");

	acm->writeurb->transfer_buffer_length = count;
	acm->writeurb->dev = acm->dev;

	acm->ready_for_write = 0;
	stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
	if (stat < 0) {
		dbg("usb_submit_urb(write bulk) failed");
		acm->ready_for_write = 1;
		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;
	return !acm->ready_for_write ? 0 : acm->writesize;
}

static int acm_tty_chars_in_buffer(struct tty_struct *tty)
{
	struct acm *acm = tty->driver_data;
	if (!ACM_READY(acm))
		return -EINVAL;
	return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
}

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);
	if (acm->resubmit_to_unthrottle) {
		acm->resubmit_to_unthrottle = 0;
		acm_read_bulk(acm->readurb, NULL);
	}
}

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;

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
欧美不卡一区二区| 欧美在线观看视频一区二区| 精品国一区二区三区| 精品少妇一区二区三区在线播放| 日韩欧美精品三级| 亚洲欧洲精品一区二区精品久久久| 亚洲综合偷拍欧美一区色| 日韩精品中文字幕在线一区| 99久久精品国产麻豆演员表| 成人免费看的视频| 亚洲成人av一区二区三区| 亚洲免费视频中文字幕| 黄页视频在线91| 丁香桃色午夜亚洲一区二区三区| 波多野结衣精品在线| 日本va欧美va精品| 久久综合色之久久综合| av一二三不卡影片| 精品影视av免费| 91精品在线麻豆| 久久久.com| 中文字幕成人av| 亚洲婷婷国产精品电影人久久| 99re这里只有精品首页| 欧美高清激情brazzers| 日韩精品一区在线| 久久综合久久综合久久综合| 欧美日韩国产一级片| 91激情五月电影| 欧美日韩激情在线| 精品日韩成人av| 国产三级欧美三级日产三级99| 久久久www免费人成精品| 国产日产欧美精品一区二区三区| 在线免费观看日本欧美| 久久99日本精品| 亚洲综合一区二区精品导航| 欧美美女直播网站| 色婷婷亚洲综合| 九九**精品视频免费播放| 亚洲精选视频在线| 久久综合久久久久88| 精品国产亚洲在线| 欧美蜜桃一区二区三区 | 亚洲一区二区三区小说| 欧美经典一区二区三区| 精品视频资源站| 国产大片一区二区| 亚洲一区二区在线播放相泽 | 一本到不卡精品视频在线观看| 国产99一区视频免费| 九九国产精品视频| 亚洲妇女屁股眼交7| 国产性做久久久久久| 欧美怡红院视频| 国产精品影视网| 日韩电影在线观看电影| 久久久精品免费网站| 9191精品国产综合久久久久久| 91国产免费观看| 狠狠色丁香久久婷婷综合_中| 亚洲免费在线视频| 久久一日本道色综合| 日韩视频在线一区二区| 色呦呦网站一区| 91在线丨porny丨国产| 欧美性生活久久| 精品久久久久久久久久久久包黑料 | 精品国产一区久久| 欧美色综合网站| 激情亚洲综合在线| 捆绑调教美女网站视频一区| 亚洲一区二区三区精品在线| 久久国产欧美日韩精品| 99国产精品99久久久久久| 精品视频999| 亚洲伊人伊色伊影伊综合网| 夜夜亚洲天天久久| 色94色欧美sute亚洲线路二| 国产精品乱码妇女bbbb| 丁香五精品蜜臀久久久久99网站 | 奇米777欧美一区二区| 91久久奴性调教| 亚洲成在人线在线播放| 日本韩国欧美一区二区三区| 久久精品视频在线免费观看| 麻豆成人91精品二区三区| 欧美精品1区2区3区| 一区二区视频在线| 欧洲精品一区二区| 亚洲欧美日韩在线| 欧美丝袜第三区| 综合激情网...| 91黄色激情网站| 一区二区中文视频| 大胆亚洲人体视频| 久久久久久免费| 在线观看亚洲专区| 精品免费视频一区二区| 亚洲一区二区偷拍精品| 一区二区三区不卡在线观看 | 欧美视频第二页| 国产精品国产三级国产a| 成人午夜在线播放| 蜜臀精品一区二区三区在线观看 | 欧美激情一区不卡| 一道本成人在线| 激情偷乱视频一区二区三区| 一区二区三区中文字幕精品精品| 欧美久久久一区| 99久久久精品| 日韩—二三区免费观看av| 日韩免费一区二区三区在线播放| 日韩高清在线不卡| 久久青草国产手机看片福利盒子| 国产一区二区三区四区在线观看| 日韩免费视频线观看| 免费精品视频在线| 欧美性欧美巨大黑白大战| 亚洲成av人片在www色猫咪| 国产欧美日韩在线| 综合自拍亚洲综合图不卡区| 国产一区在线精品| 9191久久久久久久久久久| 一卡二卡三卡日韩欧美| jlzzjlzz亚洲女人18| 国产视频一区在线观看| 麻豆精品新av中文字幕| 这里只有精品视频在线观看| 亚洲女厕所小便bbb| 波多野洁衣一区| 久久久久国产一区二区三区四区 | 无码av免费一区二区三区试看| av电影天堂一区二区在线观看| 国产性色一区二区| 国产精品资源在线观看| 精品国产亚洲一区二区三区在线观看| 蜜桃视频在线观看一区| 91麻豆精品国产91久久久| 婷婷一区二区三区| 欧美精品tushy高清| 石原莉奈一区二区三区在线观看| 欧美视频三区在线播放| 亚洲一区在线看| 欧美四级电影网| 五月天久久比比资源色| 欧美久久婷婷综合色| 日韩精品一二三区| 国产精品视频九色porn| 国产寡妇亲子伦一区二区| 久久久噜噜噜久久人人看 | 亚洲美腿欧美偷拍| 色婷婷av久久久久久久| 亚洲午夜久久久久久久久电影院| 在线视频国产一区| 午夜欧美视频在线观看| 日韩欧美亚洲国产另类| 国内外精品视频| 国产精品久久久久久久第一福利| 99热精品一区二区| 亚洲第一综合色| 欧美一区二区三区在线看| 国产伦精品一区二区三区视频青涩| 久久精品亚洲乱码伦伦中文| av动漫一区二区| 亚洲国产日产av| 精品国产91乱码一区二区三区| 国产福利91精品| 亚洲综合小说图片| 日韩欧美一区电影| 成人午夜短视频| 一个色综合av| 精品久久人人做人人爰| 成人精品视频一区| 亚洲国产wwwccc36天堂| 欧美变态凌虐bdsm| av中文字幕亚洲| 秋霞影院一区二区| 国产精品久久久久久久浪潮网站| 色妹子一区二区| 99久久99久久精品免费看蜜桃| 国产女人18水真多18精品一级做| 久久精品夜色噜噜亚洲a∨| 亚洲777理论| 欧美中文一区二区三区| 麻豆高清免费国产一区| 最好看的中文字幕久久| 日韩一级片在线观看| 国产精品1区二区.| 五月综合激情网| 中文字幕永久在线不卡| 欧美成人激情免费网| 色琪琪一区二区三区亚洲区| 久草精品在线观看| 亚洲女同一区二区| 久久精品男人的天堂| 69av一区二区三区| 91丨九色丨黑人外教| 国产一区二区在线影院| 亚洲一区二区影院|