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

📄 digi_acceleport.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	unsigned long flags = 0;	dbg("digi_close: TOP: port=%d, open_count=%d",		priv->dp_port_num, port->open_count);	/* if disconnected, just clear flags */	if (!usb_get_intfdata(port->serial->interface))		goto exit;	/* do cleanup only after final close on this port */	spin_lock_irqsave(&priv->dp_port_lock, flags);	priv->dp_in_close = 1;	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	/* tell line discipline to process only XON/XOFF */	tty->closing = 1;	/* wait for output to drain */	if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)		tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);	/* flush driver and line discipline buffers */	if (tty->driver->flush_buffer)		tty->driver->flush_buffer(tty);	tty_ldisc_flush(tty);	if (port->serial->dev) {		/* wait for transmit idle */		if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {			digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);		}		/* drop DTR and RTS */		digi_set_modem_signals(port, 0, 0);		/* disable input flow control */		buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;		buf[1] = priv->dp_port_num;		buf[2] = DIGI_DISABLE;		buf[3] = 0;		/* disable output flow control */		buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;		buf[5] = priv->dp_port_num;		buf[6] = DIGI_DISABLE;		buf[7] = 0;		/* disable reading modem signals automatically */		buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;		buf[9] = priv->dp_port_num;		buf[10] = DIGI_DISABLE;		buf[11] = 0;		/* disable receive */		buf[12] = DIGI_CMD_RECEIVE_ENABLE;		buf[13] = priv->dp_port_num;		buf[14] = DIGI_DISABLE;		buf[15] = 0;		/* flush fifos */		buf[16] = DIGI_CMD_IFLUSH_FIFO;		buf[17] = priv->dp_port_num;		buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;		buf[19] = 0;		if ((ret = digi_write_oob_command(port, buf, 20, 0)) != 0)			dbg("digi_close: write oob failed, ret=%d", ret);		/* wait for final commands on oob port to complete */		prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);		schedule_timeout(DIGI_CLOSE_TIMEOUT);		finish_wait(&priv->dp_flush_wait, &wait);		/* shutdown any outstanding bulk writes */		usb_kill_urb(port->write_urb);	}	tty->closing = 0;exit:	spin_lock_irqsave(&priv->dp_port_lock, flags);	priv->dp_write_urb_in_use = 0;	priv->dp_in_close = 0;	wake_up_interruptible(&priv->dp_close_wait);	spin_unlock_irqrestore(&priv->dp_port_lock, flags);	dbg("digi_close: done");}/**  Digi Startup Device**  Starts reads on all ports.  Must be called AFTER startup, with*  urbs initialized.  Returns 0 if successful, non-zero error otherwise.*/static int digi_startup_device(struct usb_serial *serial){	int i,ret = 0;	struct digi_serial *serial_priv = usb_get_serial_data(serial);	struct usb_serial_port *port;	/* be sure this happens exactly once */	spin_lock(&serial_priv->ds_serial_lock);	if (serial_priv->ds_device_started) {		spin_unlock(&serial_priv->ds_serial_lock);		return 0;	}	serial_priv->ds_device_started = 1;	spin_unlock(&serial_priv->ds_serial_lock);	/* start reading from each bulk in endpoint for the device */	/* set USB_DISABLE_SPD flag for write bulk urbs */	for (i = 0; i < serial->type->num_ports + 1; i++) {		port = serial->port[i];		port->write_urb->dev = port->serial->dev;		if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) {			err("%s: usb_submit_urb failed, ret=%d, port=%d",					__FUNCTION__, ret, i);			break;		}	}	return ret;}static int digi_startup(struct usb_serial *serial){	int i;	struct digi_port *priv;	struct digi_serial *serial_priv;	dbg("digi_startup: TOP");	/* allocate the private data structures for all ports */	/* number of regular ports + 1 for the out-of-band port */	for(i = 0; i < serial->type->num_ports + 1; i++) {		/* allocate port private structure */		priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL);		if (priv == NULL) {			while (--i >= 0)				kfree(usb_get_serial_port_data(serial->port[i]));			return 1;			/* error */		}		/* initialize port private structure */		spin_lock_init(&priv->dp_port_lock);		priv->dp_port_num = i;		priv->dp_out_buf_len = 0;		priv->dp_write_urb_in_use = 0;		priv->dp_modem_signals = 0;		init_waitqueue_head(&priv->dp_modem_change_wait);		priv->dp_transmit_idle = 0;		init_waitqueue_head(&priv->dp_transmit_idle_wait);		priv->dp_throttled = 0;		priv->dp_throttle_restart = 0;		init_waitqueue_head(&priv->dp_flush_wait);		priv->dp_in_close = 0;		init_waitqueue_head(&priv->dp_close_wait);		INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);		priv->dp_port = serial->port[i];		/* initialize write wait queue for this port */		init_waitqueue_head(&serial->port[i]->write_wait);		usb_set_serial_port_data(serial->port[i], priv);	}	/* allocate serial private structure */	serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL);	if (serial_priv == NULL) {		for (i = 0; i < serial->type->num_ports + 1; i++)			kfree(usb_get_serial_port_data(serial->port[i]));		return 1;			/* error */	}	/* initialize serial private structure */	spin_lock_init(&serial_priv->ds_serial_lock);	serial_priv->ds_oob_port_num = serial->type->num_ports;	serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];	serial_priv->ds_device_started = 0;	usb_set_serial_data(serial, serial_priv);	return 0;}static void digi_shutdown(struct usb_serial *serial){	int i;	dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt());	/* stop reads and writes on all ports */	for (i = 0; i < serial->type->num_ports + 1; i++) {		usb_kill_urb(serial->port[i]->read_urb);		usb_kill_urb(serial->port[i]->write_urb);	}	/* free the private data structures for all ports */	/* number of regular ports + 1 for the out-of-band port */	for(i = 0; i < serial->type->num_ports + 1; i++)		kfree(usb_get_serial_port_data(serial->port[i]));	kfree(usb_get_serial_data(serial));}static void digi_read_bulk_callback(struct urb *urb){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct digi_port *priv;	struct digi_serial *serial_priv;	int ret;	int status = urb->status;	dbg("digi_read_bulk_callback: TOP");	/* port sanity check, do not resubmit if port is not valid */	if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {		err("%s: port or port->private is NULL, status=%d",		    __FUNCTION__, status);		return;	}	if (port->serial == NULL ||		(serial_priv=usb_get_serial_data(port->serial)) == NULL) {		err("%s: serial is bad or serial->private is NULL, status=%d",			__FUNCTION__, status);		return;	}	/* do not resubmit urb if it has any status error */	if (status) {		err("%s: nonzero read bulk status: status=%d, port=%d",		    __FUNCTION__, status, priv->dp_port_num);		return;	}	/* handle oob or inb callback, do not resubmit if error */	if (priv->dp_port_num == serial_priv->ds_oob_port_num) {		if (digi_read_oob_callback(urb) != 0)			return;	} else {		if (digi_read_inb_callback(urb) != 0)			return;	}	/* continue read */	urb->dev = port->serial->dev;	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {		err("%s: failed resubmitting urb, ret=%d, port=%d",		    __FUNCTION__, ret, priv->dp_port_num);	}}/* *  Digi Read INB Callback**  Digi Read INB Callback handles reads on the in band ports, sending*  the data on to the tty subsystem.  When called we know port and*  port->private are not NULL and port->serial has been validated.*  It returns 0 if successful, 1 if successful but the port is*  throttled, and -1 if the sanity checks failed.*/static int digi_read_inb_callback(struct urb *urb){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct tty_struct *tty = port->tty;	struct digi_port *priv = usb_get_serial_port_data(port);	int opcode = ((unsigned char *)urb->transfer_buffer)[0];	int len = ((unsigned char *)urb->transfer_buffer)[1];	int port_status = ((unsigned char *)urb->transfer_buffer)[2];	unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;	int flag,throttled;	int i;	int status = urb->status;	/* do not process callbacks on closed ports */	/* but do continue the read chain */	if (port->open_count == 0)		return 0;	/* short/multiple packet check */	if (urb->actual_length != len + 2) {     		err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, "		    "port=%d, opcode=%d, len=%d, actual_length=%d, "		    "status=%d", __FUNCTION__, status, priv->dp_port_num,		    opcode, len, urb->actual_length, port_status);		return -1;	}	spin_lock(&priv->dp_port_lock);	/* check for throttle; if set, do not resubmit read urb */	/* indicate the read chain needs to be restarted on unthrottle */	throttled = priv->dp_throttled;	if (throttled)		priv->dp_throttle_restart = 1;	/* receive data */	if (opcode == DIGI_CMD_RECEIVE_DATA) {		/* get flag from port_status */		flag = 0;		/* overrun is special, not associated with a char */		if (port_status & DIGI_OVERRUN_ERROR)			tty_insert_flip_char(tty, 0, TTY_OVERRUN);		/* break takes precedence over parity, */		/* which takes precedence over framing errors */		if (port_status & DIGI_BREAK_ERROR)			flag = TTY_BREAK;		else if (port_status & DIGI_PARITY_ERROR)			flag = TTY_PARITY;		else if (port_status & DIGI_FRAMING_ERROR)			flag = TTY_FRAME;		/* data length is len-1 (one byte of len is port_status) */		--len;		len = tty_buffer_request_room(tty, len);		if (len > 0) {			/* Hot path */			if (flag == TTY_NORMAL)				tty_insert_flip_string(tty, data, len);			else {				for(i = 0; i < len; i++)					tty_insert_flip_char(tty, data[i], flag);			}			tty_flip_buffer_push(tty);		}	}	spin_unlock(&priv->dp_port_lock);	if (opcode == DIGI_CMD_RECEIVE_DISABLE)		dbg("%s: got RECEIVE_DISABLE", __FUNCTION__);	else if (opcode != DIGI_CMD_RECEIVE_DATA)		dbg("%s: unknown opcode: %d", __FUNCTION__, opcode);	return(throttled ? 1 : 0);}/* *  Digi Read OOB Callback**  Digi Read OOB Callback handles reads on the out of band port.*  When called we know port and port->private are not NULL and*  the port->serial is valid.  It returns 0 if successful, and*  -1 if the sanity checks failed.*/static int digi_read_oob_callback(struct urb *urb){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct usb_serial *serial = port->serial;	struct digi_port *priv = usb_get_serial_port_data(port);	int opcode, line, status, val;	int i;	dbg("digi_read_oob_callback: port=%d, len=%d",			priv->dp_port_num, urb->actual_length);	/* handle each oob command */	for(i = 0; i < urb->actual_length - 3;) {		opcode = ((unsigned char *)urb->transfer_buffer)[i++];		line = ((unsigned char *)urb->transfer_buffer)[i++];		status = ((unsigned char *)urb->transfer_buffer)[i++];		val = ((unsigned char *)urb->transfer_buffer)[i++];		dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",			opcode, line, status, val);		if (status != 0 || line >= serial->type->num_ports)			continue;		port = serial->port[line];		if ((priv=usb_get_serial_port_data(port)) == NULL)			return -1;		if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {			spin_lock(&priv->dp_port_lock);			/* convert from digi flags to termiox flags */			if (val & DIGI_READ_INPUT_SIGNALS_CTS) {				priv->dp_modem_signals |= TIOCM_CTS;				/* port must be open to use tty struct */				if (port->open_count					&& port->tty->termios->c_cflag & CRTSCTS) {					port->tty->hw_stopped = 0;					digi_wakeup_write(port);				}			} else {				priv->dp_modem_signals &= ~TIOCM_CTS;				/* port must be open to use tty struct */				if (port->open_count					&& port->tty->termios->c_cflag & CRTSCTS) {					port->tty->hw_stopped = 1;				}			}			if (val & DIGI_READ_INPUT_SIGNALS_DSR)				priv->dp_modem_signals |= TIOCM_DSR;			else				priv->dp_modem_signals &= ~TIOCM_DSR;			if (val & DIGI_READ_INPUT_SIGNALS_RI)				priv->dp_modem_signals |= TIOCM_RI;			else				priv->dp_modem_signals &= ~TIOCM_RI;			if (val & DIGI_READ_INPUT_SIGNALS_DCD)				priv->dp_modem_signals |= TIOCM_CD;			else				priv->dp_modem_signals &= ~TIOCM_CD;			wake_up_interruptible(&priv->dp_modem_change_wait);			spin_unlock(&priv->dp_port_lock);		} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {			spin_lock(&priv->dp_port_lock);			priv->dp_transmit_idle = 1;			wake_up_interruptible(&priv->dp_transmit_idle_wait);			spin_unlock(&priv->dp_port_lock);		} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {			wake_up_interruptible(&priv->dp_flush_wait);		}	}	return 0;}static int __init digi_init(void){	int retval;	retval = usb_serial_register(&digi_acceleport_2_device);	if (retval)		goto failed_acceleport_2_device;	retval = usb_serial_register(&digi_acceleport_4_device);	if (retval) 		goto failed_acceleport_4_device;	retval = usb_register(&digi_driver);	if (retval)		goto failed_usb_register;	info(DRIVER_VERSION ":" DRIVER_DESC);	return 0;failed_usb_register:	usb_serial_deregister(&digi_acceleport_4_device);failed_acceleport_4_device:	usb_serial_deregister(&digi_acceleport_2_device);failed_acceleport_2_device:	return retval;}static void __exit digi_exit (void){	usb_deregister(&digi_driver);	usb_serial_deregister(&digi_acceleport_2_device);	usb_serial_deregister(&digi_acceleport_4_device);}module_init(digi_init);module_exit(digi_exit);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");

⌨️ 快捷键说明

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