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

📄 tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);	if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {		if (dev->tty && !C_CLOCAL(dev->tty))			tty_hangup(dev->tty);	}	dev->modem_status = 		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);}/* ---- TTY functions ---- */static void rfcomm_tty_wakeup(unsigned long arg){	struct rfcomm_dev *dev = (void *) arg;	struct tty_struct *tty = dev->tty;	if (!tty)		return;	BT_DBG("dev %p tty %p", dev, tty);	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)                (tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);#ifdef SERIAL_HAVE_POLL_WAIT	wake_up_interruptible(&tty->poll_wait);#endif}static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp){	DECLARE_WAITQUEUE(wait, current);	struct rfcomm_dev *dev;	struct rfcomm_dlc *dlc;	int err, id;        id = tty->index;	BT_DBG("tty %p id %d", tty, id);	/* We don't leak this refcount. For reasons which are not entirely	   clear, the TTY layer will call our ->close() method even if the	   open fails. We decrease the refcount there, and decreasing it	   here too would cause breakage. */	dev = rfcomm_dev_get(id);	if (!dev)		return -ENODEV;	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);	if (dev->opened++ != 0)		return 0;	dlc = dev->dlc;	/* Attach TTY and open DLC */	rfcomm_dlc_lock(dlc);	tty->driver_data = dev;	dev->tty = tty;	rfcomm_dlc_unlock(dlc);	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);	if (err < 0)		return err;	/* Wait for DLC to connect */	add_wait_queue(&dev->wait, &wait);	while (1) {		set_current_state(TASK_INTERRUPTIBLE);		if (dlc->state == BT_CLOSED) {			err = -dev->err;			break;		}		if (dlc->state == BT_CONNECTED)			break;		if (signal_pending(current)) {			err = -EINTR;			break;		}		schedule();	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&dev->wait, &wait);	return err;}static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	if (!dev)		return;	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);	if (--dev->opened == 0) {		/* Close DLC and dettach TTY */		rfcomm_dlc_close(dev->dlc, 0);		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);		tasklet_kill(&dev->wakeup_task);		rfcomm_dlc_lock(dev->dlc);		tty->driver_data = NULL;		dev->tty = NULL;		rfcomm_dlc_unlock(dev->dlc);	}	rfcomm_dev_put(dev);}static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	struct rfcomm_dlc *dlc = dev->dlc;	struct sk_buff *skb;	int err = 0, sent = 0, size;	BT_DBG("tty %p count %d", tty, count);	while (count) {		size = min_t(uint, count, dlc->mtu);		skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, GFP_ATOMIC);				if (!skb)			break;		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);		memcpy(skb_put(skb, size), buf + sent, size);		if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {			kfree_skb(skb);			break;		}		sent  += size;		count -= size;	}	return sent ? sent : err;}static int rfcomm_tty_write_room(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	int room;	BT_DBG("tty %p", tty);	room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);	if (room < 0)		room = 0;	return room;}static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg){	BT_DBG("tty %p cmd 0x%02x", tty, cmd);	switch (cmd) {	case TCGETS:		BT_DBG("TCGETS is not supported");		return -ENOIOCTLCMD;	case TCSETS:		BT_DBG("TCSETS is not supported");		return -ENOIOCTLCMD;	case TIOCMIWAIT:		BT_DBG("TIOCMIWAIT");		break;	case TIOCGICOUNT:		BT_DBG("TIOCGICOUNT");		break;	case TIOCGSERIAL:		BT_ERR("TIOCGSERIAL is not supported");		return -ENOIOCTLCMD;	case TIOCSSERIAL:		BT_ERR("TIOCSSERIAL is not supported");		return -ENOIOCTLCMD;	case TIOCSERGSTRUCT:		BT_ERR("TIOCSERGSTRUCT is not supported");		return -ENOIOCTLCMD;	case TIOCSERGETLSR:		BT_ERR("TIOCSERGETLSR is not supported");		return -ENOIOCTLCMD;	case TIOCSERCONFIG:		BT_ERR("TIOCSERCONFIG is not supported");		return -ENOIOCTLCMD;	default:		return -ENOIOCTLCMD;	/* ioctls which we must ignore */	}	return -ENOIOCTLCMD;}static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old){	struct termios *new = (struct termios *) tty->termios;	int old_baud_rate = tty_termios_baud_rate(old);	int new_baud_rate = tty_termios_baud_rate(new);	u8 baud, data_bits, stop_bits, parity, x_on, x_off;	u16 changes = 0;	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	BT_DBG("tty %p termios %p", tty, old);	/* Handle turning off CRTSCTS */	if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS)) 		BT_DBG("Turning off CRTSCTS unsupported");	/* Parity on/off and when on, odd/even */	if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) ||			((old->c_cflag & PARODD) != (new->c_cflag & PARODD)) ) {		changes |= RFCOMM_RPN_PM_PARITY;		BT_DBG("Parity change detected.");	}	/* Mark and space parity are not supported! */	if (new->c_cflag & PARENB) {		if (new->c_cflag & PARODD) {			BT_DBG("Parity is ODD");			parity = RFCOMM_RPN_PARITY_ODD;		} else {			BT_DBG("Parity is EVEN");			parity = RFCOMM_RPN_PARITY_EVEN;		}	} else {		BT_DBG("Parity is OFF");		parity = RFCOMM_RPN_PARITY_NONE;	}	/* Setting the x_on / x_off characters */	if (old->c_cc[VSTOP] != new->c_cc[VSTOP]) {		BT_DBG("XOFF custom");		x_on = new->c_cc[VSTOP];		changes |= RFCOMM_RPN_PM_XON;	} else {		BT_DBG("XOFF default");		x_on = RFCOMM_RPN_XON_CHAR;	}	if (old->c_cc[VSTART] != new->c_cc[VSTART]) {		BT_DBG("XON custom");		x_off = new->c_cc[VSTART];		changes |= RFCOMM_RPN_PM_XOFF;	} else {		BT_DBG("XON default");		x_off = RFCOMM_RPN_XOFF_CHAR;	}	/* Handle setting of stop bits */	if ((old->c_cflag & CSTOPB) != (new->c_cflag & CSTOPB))		changes |= RFCOMM_RPN_PM_STOP;	/* POSIX does not support 1.5 stop bits and RFCOMM does not	 * support 2 stop bits. So a request for 2 stop bits gets	 * translated to 1.5 stop bits */	if (new->c_cflag & CSTOPB) {		stop_bits = RFCOMM_RPN_STOP_15;	} else {		stop_bits = RFCOMM_RPN_STOP_1;	}	/* Handle number of data bits [5-8] */	if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE)) 		changes |= RFCOMM_RPN_PM_DATA;	switch (new->c_cflag & CSIZE) {	case CS5:		data_bits = RFCOMM_RPN_DATA_5;		break;	case CS6:		data_bits = RFCOMM_RPN_DATA_6;		break;	case CS7:		data_bits = RFCOMM_RPN_DATA_7;		break;	case CS8:		data_bits = RFCOMM_RPN_DATA_8;		break;	default:		data_bits = RFCOMM_RPN_DATA_8;		break;	}	/* Handle baudrate settings */	if (old_baud_rate != new_baud_rate)		changes |= RFCOMM_RPN_PM_BITRATE;	switch (new_baud_rate) {	case 2400:		baud = RFCOMM_RPN_BR_2400;		break;	case 4800:		baud = RFCOMM_RPN_BR_4800;		break;	case 7200:		baud = RFCOMM_RPN_BR_7200;		break;	case 9600:		baud = RFCOMM_RPN_BR_9600;		break;	case 19200: 		baud = RFCOMM_RPN_BR_19200;		break;	case 38400:		baud = RFCOMM_RPN_BR_38400;		break;	case 57600:		baud = RFCOMM_RPN_BR_57600;		break;	case 115200:		baud = RFCOMM_RPN_BR_115200;		break;	case 230400:		baud = RFCOMM_RPN_BR_230400;		break;	default:		/* 9600 is standard accordinag to the RFCOMM specification */		baud = RFCOMM_RPN_BR_9600;		break;		}	if (changes)		rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,				data_bits, stop_bits, parity,				RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);	return;}static void rfcomm_tty_throttle(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	BT_DBG("tty %p dev %p", tty, dev);	rfcomm_dlc_throttle(dev->dlc);}static void rfcomm_tty_unthrottle(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	BT_DBG("tty %p dev %p", tty, dev);	rfcomm_dlc_unthrottle(dev->dlc);}static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	struct rfcomm_dlc *dlc = dev->dlc;	BT_DBG("tty %p dev %p", tty, dev);	if (!skb_queue_empty(&dlc->tx_queue))		return dlc->mtu;	return 0;}static void rfcomm_tty_flush_buffer(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	if (!dev)		return;	BT_DBG("tty %p dev %p", tty, dev);	skb_queue_purge(&dev->dlc->tx_queue);	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)		tty->ldisc.write_wakeup(tty);}static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch){	BT_DBG("tty %p ch %c", tty, ch);}static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout){	BT_DBG("tty %p timeout %d", tty, timeout);}static void rfcomm_tty_hangup(struct tty_struct *tty){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	if (!dev)		return;	BT_DBG("tty %p dev %p", tty, dev);	rfcomm_tty_flush_buffer(tty);	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))		rfcomm_dev_del(dev);}static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused){	return 0;}static int rfcomm_tty_tiocmget(struct tty_struct *tty, struct file *filp){ 	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	BT_DBG("tty %p dev %p", tty, dev); 	return dev->modem_status;}static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsigned int set, unsigned int clear){	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;	struct rfcomm_dlc *dlc = dev->dlc;	u8 v24_sig;	BT_DBG("tty %p dev %p set 0x%02x clear 0x%02x", tty, dev, set, clear);	rfcomm_dlc_get_modem_status(dlc, &v24_sig);	if (set & TIOCM_DSR || set & TIOCM_DTR)		v24_sig |= RFCOMM_V24_RTC;	if (set & TIOCM_RTS || set & TIOCM_CTS)		v24_sig |= RFCOMM_V24_RTR;	if (set & TIOCM_RI)		v24_sig |= RFCOMM_V24_IC;	if (set & TIOCM_CD)		v24_sig |= RFCOMM_V24_DV;	if (clear & TIOCM_DSR || clear & TIOCM_DTR)		v24_sig &= ~RFCOMM_V24_RTC;	if (clear & TIOCM_RTS || clear & TIOCM_CTS)		v24_sig &= ~RFCOMM_V24_RTR;	if (clear & TIOCM_RI)		v24_sig &= ~RFCOMM_V24_IC;	if (clear & TIOCM_CD)		v24_sig &= ~RFCOMM_V24_DV;	rfcomm_dlc_set_modem_status(dlc, v24_sig);	return 0;}/* ---- TTY structure ---- */static struct tty_operations rfcomm_ops = {	.open			= rfcomm_tty_open,	.close			= rfcomm_tty_close,	.write			= rfcomm_tty_write,	.write_room		= rfcomm_tty_write_room,	.chars_in_buffer	= rfcomm_tty_chars_in_buffer,	.flush_buffer		= rfcomm_tty_flush_buffer,	.ioctl			= rfcomm_tty_ioctl,	.throttle		= rfcomm_tty_throttle,	.unthrottle		= rfcomm_tty_unthrottle,	.set_termios		= rfcomm_tty_set_termios,	.send_xchar		= rfcomm_tty_send_xchar,	.hangup			= rfcomm_tty_hangup,	.wait_until_sent	= rfcomm_tty_wait_until_sent,	.read_proc		= rfcomm_tty_read_proc,	.tiocmget		= rfcomm_tty_tiocmget,	.tiocmset		= rfcomm_tty_tiocmset,};int rfcomm_init_ttys(void){	rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);	if (!rfcomm_tty_driver)		return -1;	rfcomm_tty_driver->owner	= THIS_MODULE;	rfcomm_tty_driver->driver_name	= "rfcomm";	rfcomm_tty_driver->devfs_name	= "bluetooth/rfcomm/";	rfcomm_tty_driver->name		= "rfcomm";	rfcomm_tty_driver->major	= RFCOMM_TTY_MAJOR;	rfcomm_tty_driver->minor_start	= RFCOMM_TTY_MINOR;	rfcomm_tty_driver->type		= TTY_DRIVER_TYPE_SERIAL;	rfcomm_tty_driver->subtype	= SERIAL_TYPE_NORMAL;	rfcomm_tty_driver->flags	= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;	rfcomm_tty_driver->init_termios	= tty_std_termios;	rfcomm_tty_driver->init_termios.c_cflag	= B9600 | CS8 | CREAD | HUPCL | CLOCAL;	tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);	if (tty_register_driver(rfcomm_tty_driver)) {		BT_ERR("Can't register RFCOMM TTY driver");		put_tty_driver(rfcomm_tty_driver);		return -1;	}	BT_INFO("RFCOMM TTY layer initialized");	return 0;}void rfcomm_cleanup_ttys(void){	tty_unregister_driver(rfcomm_tty_driver);	put_tty_driver(rfcomm_tty_driver);}

⌨️ 快捷键说明

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