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

📄 digi_acceleport.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Statics */static int debug;static struct usb_device_id id_table_combined [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },	{ }						/* Terminating entry */};static struct usb_device_id id_table_2 [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },	{ }						/* Terminating entry */};static struct usb_device_id id_table_4 [] = {	{ USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },	{ }						/* Terminating entry */};MODULE_DEVICE_TABLE (usb, id_table_combined);static struct usb_driver digi_driver = {	.name =		"digi_acceleport",	.probe =	usb_serial_probe,	.disconnect =	usb_serial_disconnect,	.id_table =	id_table_combined,	.no_dynamic_id = 	1,};/* device info needed for the Digi serial converter */static struct usb_serial_driver digi_acceleport_2_device = {	.driver = {		.owner =		THIS_MODULE,		.name =			"digi_2",	},	.description =			"Digi 2 port USB adapter",	.usb_driver = 			&digi_driver,	.id_table =			id_table_2,	.num_interrupt_in =		0,	.num_bulk_in =			4,	.num_bulk_out =			4,	.num_ports =			3,	.open =				digi_open,	.close =			digi_close,	.write =			digi_write,	.write_room =			digi_write_room,	.write_bulk_callback = 		digi_write_bulk_callback,	.read_bulk_callback =		digi_read_bulk_callback,	.chars_in_buffer =		digi_chars_in_buffer,	.throttle =			digi_rx_throttle,	.unthrottle =			digi_rx_unthrottle,	.ioctl =			digi_ioctl,	.set_termios =			digi_set_termios,	.break_ctl =			digi_break_ctl,	.tiocmget =			digi_tiocmget,	.tiocmset =			digi_tiocmset,	.attach =			digi_startup,	.shutdown =			digi_shutdown,};static struct usb_serial_driver digi_acceleport_4_device = {	.driver = {		.owner =		THIS_MODULE,		.name =			"digi_4",	},	.description =			"Digi 4 port USB adapter",	.usb_driver = 			&digi_driver,	.id_table =			id_table_4,	.num_interrupt_in =		0,	.num_bulk_in =			5,	.num_bulk_out =			5,	.num_ports =			4,	.open =				digi_open,	.close =			digi_close,	.write =			digi_write,	.write_room =			digi_write_room,	.write_bulk_callback = 		digi_write_bulk_callback,	.read_bulk_callback =		digi_read_bulk_callback,	.chars_in_buffer =		digi_chars_in_buffer,	.throttle =			digi_rx_throttle,	.unthrottle =			digi_rx_unthrottle,	.ioctl =			digi_ioctl,	.set_termios =			digi_set_termios,	.break_ctl =			digi_break_ctl,	.tiocmget =			digi_tiocmget,	.tiocmset =			digi_tiocmset,	.attach =			digi_startup,	.shutdown =			digi_shutdown,};/* Functions *//**  Cond Wait Interruptible Timeout Irqrestore**  Do spin_unlock_irqrestore and interruptible_sleep_on_timeout*  so that wake ups are not lost if they occur between the unlock*  and the sleep.  In other words, spin_unlock_irqrestore and*  interruptible_sleep_on_timeout are "atomic" with respect to*  wake ups.  This is used to implement condition variables.**  interruptible_sleep_on_timeout is deprecated and has been replaced*  with the equivalent code.*/static long cond_wait_interruptible_timeout_irqrestore(	wait_queue_head_t *q, long timeout,	spinlock_t *lock, unsigned long flags){	DEFINE_WAIT(wait);	prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);	spin_unlock_irqrestore(lock, flags);	timeout = schedule_timeout(timeout);	finish_wait(q, &wait);	return timeout;}/**  Digi Wakeup Write**  Wake up port, line discipline, and tty processes sleeping*  on writes.*/static void digi_wakeup_write_lock(struct work_struct *work){	struct digi_port *priv = container_of(work, struct digi_port, dp_wakeup_work);	struct usb_serial_port *port = priv->dp_port;	unsigned long flags;	spin_lock_irqsave(&priv->dp_port_lock, flags);	digi_wakeup_write(port);	spin_unlock_irqrestore(&priv->dp_port_lock, flags);}static void digi_wakeup_write(struct usb_serial_port *port){	tty_wakeup(port->tty);}/**  Digi Write OOB Command**  Write commands on the out of band port.  Commands are 4*  bytes each, multiple commands can be sent at once, and*  no command will be split across USB packets.  Returns 0*  if successful, -EINTR if interrupted while sleeping and*  the interruptible flag is true, or a negative error*  returned by usb_submit_urb.*/static int digi_write_oob_command(struct usb_serial_port *port,	unsigned char *buf, int count, int interruptible){	int ret = 0;	int len;	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);	unsigned long flags = 0;	dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count);	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);	while(count > 0) {		while(oob_port->write_urb->status == -EINPROGRESS			|| oob_priv->dp_write_urb_in_use) {			cond_wait_interruptible_timeout_irqrestore(				&oob_port->write_wait, DIGI_RETRY_TIMEOUT,				&oob_priv->dp_port_lock, flags);			if (interruptible && signal_pending(current))				return -EINTR;			spin_lock_irqsave(&oob_priv->dp_port_lock, flags);		}		/* len must be a multiple of 4, so commands are not split */		len = min(count, oob_port->bulk_out_size);		if (len > 4)			len &= ~3;		memcpy(oob_port->write_urb->transfer_buffer, buf, len);		oob_port->write_urb->transfer_buffer_length = len;		oob_port->write_urb->dev = port->serial->dev;		if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {			oob_priv->dp_write_urb_in_use = 1;			count -= len;			buf += len;		}	}	spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);	if (ret)		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);	return ret;}/**  Digi Write In Band Command**  Write commands on the given port.  Commands are 4*  bytes each, multiple commands can be sent at once, and*  no command will be split across USB packets.  If timeout*  is non-zero, write in band command will return after*  waiting unsuccessfully for the URB status to clear for*  timeout ticks.  Returns 0 if successful, or a negative*  error returned by digi_write.*/static int digi_write_inb_command(struct usb_serial_port *port,	unsigned char *buf, int count, unsigned long timeout){	int ret = 0;	int len;	struct digi_port *priv = usb_get_serial_port_data(port);	unsigned char *data = port->write_urb->transfer_buffer;	unsigned long flags = 0;	dbg("digi_write_inb_command: TOP: port=%d, count=%d",		priv->dp_port_num, count);	if (timeout)		timeout += jiffies;	else		timeout = ULONG_MAX;	spin_lock_irqsave(&priv->dp_port_lock, flags);	while(count > 0 && ret == 0) {		while((port->write_urb->status == -EINPROGRESS			|| priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {			cond_wait_interruptible_timeout_irqrestore(				&port->write_wait, DIGI_RETRY_TIMEOUT,				&priv->dp_port_lock, flags);			if (signal_pending(current))				return -EINTR;			spin_lock_irqsave(&priv->dp_port_lock, flags);		}		/* len must be a multiple of 4 and small enough to */		/* guarantee the write will send buffered data first, */		/* so commands are in order with data and not split */		len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);		if (len > 4)			len &= ~3;		/* write any buffered data first */		if (priv->dp_out_buf_len > 0) {			data[0] = DIGI_CMD_SEND_DATA;			data[1] = priv->dp_out_buf_len;			memcpy(data + 2, priv->dp_out_buf,				priv->dp_out_buf_len);			memcpy(data + 2 + priv->dp_out_buf_len, buf, len);			port->write_urb->transfer_buffer_length				= priv->dp_out_buf_len + 2 + len;		} else {			memcpy(data, buf, len);			port->write_urb->transfer_buffer_length = len;		}		port->write_urb->dev = port->serial->dev;		if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {			priv->dp_write_urb_in_use = 1;			priv->dp_out_buf_len = 0;			count -= len;			buf += len;		}	}	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	if (ret)		err("%s: usb_submit_urb failed, ret=%d, port=%d",			__FUNCTION__, ret, priv->dp_port_num);	return ret;}/**  Digi Set Modem Signals**  Sets or clears DTR and RTS on the port, according to the*  modem_signals argument.  Use TIOCM_DTR and TIOCM_RTS flags*  for the modem_signals argument.  Returns 0 if successful,*  -EINTR if interrupted while sleeping, or a non-zero error*  returned by usb_submit_urb.*/static int digi_set_modem_signals(struct usb_serial_port *port,	unsigned int modem_signals, int interruptible){	int ret;	struct digi_port *port_priv = usb_get_serial_port_data(port);	struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port;	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);	unsigned char *data = oob_port->write_urb->transfer_buffer;	unsigned long flags = 0;	dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",		port_priv->dp_port_num, modem_signals);	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);	spin_lock(&port_priv->dp_port_lock);	while(oob_port->write_urb->status == -EINPROGRESS || oob_priv->dp_write_urb_in_use) {		spin_unlock(&port_priv->dp_port_lock);		cond_wait_interruptible_timeout_irqrestore(			&oob_port->write_wait, DIGI_RETRY_TIMEOUT,			&oob_priv->dp_port_lock, flags);		if (interruptible && signal_pending(current))			return -EINTR;		spin_lock_irqsave(&oob_priv->dp_port_lock, flags);		spin_lock(&port_priv->dp_port_lock);	}	data[0] = DIGI_CMD_SET_DTR_SIGNAL;	data[1] = port_priv->dp_port_num;	data[2] = (modem_signals&TIOCM_DTR) ? DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;	data[3] = 0;	data[4] = DIGI_CMD_SET_RTS_SIGNAL;	data[5] = port_priv->dp_port_num;	data[6] = (modem_signals&TIOCM_RTS) ? DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;	data[7] = 0;	oob_port->write_urb->transfer_buffer_length = 8;	oob_port->write_urb->dev = port->serial->dev;	if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {		oob_priv->dp_write_urb_in_use = 1;		port_priv->dp_modem_signals =			(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))			| (modem_signals&(TIOCM_DTR|TIOCM_RTS));	}	spin_unlock(&port_priv->dp_port_lock);	spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);	if (ret)		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);	return ret;}/**  Digi Transmit Idle**  Digi transmit idle waits, up to timeout ticks, for the transmitter*  to go idle.  It returns 0 if successful or a negative error.**  There are race conditions here if more than one process is calling*  digi_transmit_idle on the same port at the same time.  However, this*  is only called from close, and only one process can be in close on a*  port at a time, so its ok.*/static int digi_transmit_idle(struct usb_serial_port *port,	unsigned long timeout){	int ret;	unsigned char buf[2];	struct digi_port *priv = usb_get_serial_port_data(port);	unsigned long flags = 0;	spin_lock_irqsave(&priv->dp_port_lock, flags);	priv->dp_transmit_idle = 0;	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	buf[0] = DIGI_CMD_TRANSMIT_IDLE;	buf[1] = 0;	timeout += jiffies;	if ((ret = digi_write_inb_command(port, buf, 2, timeout - jiffies)) != 0)		return ret;	spin_lock_irqsave(&priv->dp_port_lock, flags);	while(time_before(jiffies, timeout) && !priv->dp_transmit_idle) {		cond_wait_interruptible_timeout_irqrestore(			&priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,			&priv->dp_port_lock, flags);		if (signal_pending(current))			return -EINTR;		spin_lock_irqsave(&priv->dp_port_lock, flags);	}	priv->dp_transmit_idle = 0;	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	return 0;}static void digi_rx_throttle(struct usb_serial_port *port){	unsigned long flags;	struct digi_port *priv = usb_get_serial_port_data(port);	dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);	/* stop receiving characters by not resubmitting the read urb */	spin_lock_irqsave(&priv->dp_port_lock, flags);	priv->dp_throttled = 1;	priv->dp_throttle_restart = 0;	spin_unlock_irqrestore(&priv->dp_port_lock, flags);}static void digi_rx_unthrottle(struct usb_serial_port *port){	int ret = 0;	unsigned long flags;	struct digi_port *priv = usb_get_serial_port_data(port);	dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);	spin_lock_irqsave(&priv->dp_port_lock, flags);	/* turn throttle off */	priv->dp_throttled = 0;	priv->dp_throttle_restart = 0;	/* restart read chain */	if (priv->dp_throttle_restart) {		port->read_urb->dev = port->serial->dev;		ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);	}	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	if (ret)		err("%s: usb_submit_urb failed, ret=%d, port=%d",			__FUNCTION__, ret, priv->dp_port_num);}static void digi_set_termios(struct usb_serial_port *port,					struct ktermios *old_termios){	struct digi_port *priv = usb_get_serial_port_data(port);	struct tty_struct *tty = port->tty;	unsigned int iflag = tty->termios->c_iflag;	unsigned int cflag = tty->termios->c_cflag;	unsigned int old_iflag = old_termios->c_iflag;	unsigned int old_cflag = old_termios->c_cflag;	unsigned char buf[32];	unsigned int modem_signals;	int arg,ret;	int i = 0;	speed_t baud;	dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag);	/* set baud rate */	if ((baud = tty_get_baud_rate(tty)) != tty_termios_baud_rate(old_termios)) {		arg = -1;		/* reassert DTR and (maybe) RTS on transition from B0 */		if ((old_cflag&CBAUD) == B0) {			/* don't set RTS if using hardware flow control */			/* and throttling input */			modem_signals = TIOCM_DTR;			if (!(tty->termios->c_cflag & CRTSCTS) ||			    !test_bit(TTY_THROTTLED, &tty->flags))

⌨️ 快捷键说明

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