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

📄 keyspan_pda.c

📁 基于S3CEB2410平台LINUX操作系统下 USB驱动源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	case TIOCMBIS: /* set bits in bitmask <arg> */	case TIOCMBIC: /* clear bits from bitmask <arg> */		if (copy_from_user(&value, (unsigned int *)arg, sizeof(int)))			return -EFAULT;		rc = keyspan_pda_get_modem_info(serial, &status);		if (rc < 0)			return rc;		mask =			((value & TIOCM_RTS) ? (1<<2) : 0) |			((value & TIOCM_DTR) ? (1<<7) : 0);		if (cmd == TIOCMBIS)			status |= mask;		else			status &= ~mask;		rc = keyspan_pda_set_modem_info(serial, status);		if (rc < 0)			return rc;		return 0;	case TIOCMIWAIT:		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/		/* TODO */	case TIOCGICOUNT:		/* return count of modemline transitions */		return 0; /* TODO */	}		return -ENOIOCTLCMD;}static int keyspan_pda_write(struct usb_serial_port *port, int from_user, 			     const unsigned char *buf, int count){	struct usb_serial *serial = port->serial;	int request_unthrottle = 0;	int rc = 0;	struct keyspan_pda_private *priv;	priv = (struct keyspan_pda_private *)(port->private);	/* guess how much room is left in the device's ring buffer, and if we	   want to send more than that, check first, updating our notion of	   what is left. If our write will result in no room left, ask the	   device to give us an interrupt when the room available rises above	   a threshold, and hold off all writers (eventually, those using	   select() or poll() too) until we receive that unthrottle interrupt.	   Block if we can't write anything at all, otherwise write as much as	   we can. */	dbg("keyspan_pda_write(%d)",count);	if (count == 0) {		dbg(" write request of 0 bytes");		return (0);	}	/* we might block because of:	   the TX urb is in-flight (wait until it completes)	   the device is full (wait until it says there is room)	*/	if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {		return( 0 );	}	/* At this point the URB is in our control, nobody else can submit it	   again (the only sudden transition was the one from EINPROGRESS to	   finished).  Also, the tx process is not throttled. So we are	   ready to write. */	count = (count > port->bulk_out_size) ? port->bulk_out_size : count;	/* Check if we might overrun the Tx buffer.   If so, ask the	   device how much room it really has.  This is done only on	   scheduler time, since usb_control_msg() sleeps. */	if (count > priv->tx_room && !in_interrupt()) {		unsigned char room;		rc = usb_control_msg(serial->dev, 				     usb_rcvctrlpipe(serial->dev, 0),				     6, /* write_room */				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE				     | USB_DIR_IN,				     0, /* value: 0 means "remaining room" */				     0, /* index */				     &room,				     1,				     2*HZ);		if (rc < 0) {			dbg(" roomquery failed");			goto exit;		}		if (rc == 0) {			dbg(" roomquery returned 0 bytes");			rc = -EIO; /* device didn't return any data */			goto exit;		}		dbg(" roomquery says %d", room);		priv->tx_room = room;	}	if (count > priv->tx_room) {		/* we're about to completely fill the Tx buffer, so		   we'll be throttled afterwards. */		count = priv->tx_room;		request_unthrottle = 1;	}	if (count) {		/* now transfer data */		if (from_user) {			if( copy_from_user(port->write_urb->transfer_buffer,			buf, count) ) {				rc = -EFAULT;				goto exit;			}		}		else {			memcpy (port->write_urb->transfer_buffer, buf, count);		}  		/* send the data out the bulk port */		port->write_urb->transfer_buffer_length = count;				priv->tx_room -= count;		port->write_urb->dev = port->serial->dev;		rc = usb_submit_urb(port->write_urb);		if (rc) {			dbg(" usb_submit_urb(write bulk) failed");			goto exit;		}	}	else {		/* There wasn't any room left, so we are throttled until		   the buffer empties a bit */		request_unthrottle = 1;	}	if (request_unthrottle) {		priv->tx_throttled = 1; /* block writers */		MOD_INC_USE_COUNT;		if (schedule_task(&priv->unthrottle_task) == 0)			MOD_DEC_USE_COUNT;	}	rc = count;exit:	return rc;}static void keyspan_pda_write_bulk_callback (struct urb *urb){	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;	struct usb_serial *serial;	struct keyspan_pda_private *priv;	priv = (struct keyspan_pda_private *)(port->private);	if (port_paranoia_check (port, "keyspan_pda_rx_interrupt")) {		return;	}	serial = port->serial;	if (serial_paranoia_check (serial, "keyspan_pda_rx_interrupt")) {		return;	}		/* queue up a wakeup at scheduler time */	MOD_INC_USE_COUNT;	if (schedule_task(&priv->wakeup_task) == 0)		MOD_DEC_USE_COUNT;}static int keyspan_pda_write_room (struct usb_serial_port *port){	struct keyspan_pda_private *priv;	priv = (struct keyspan_pda_private *)(port->private);	/* used by n_tty.c for processing of tabs and such. Giving it our	   conservative guess is probably good enough, but needs testing by	   running a console through the device. */	return (priv->tx_room);}static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port){	struct keyspan_pda_private *priv;	priv = (struct keyspan_pda_private *)(port->private);		/* when throttled, return at least WAKEUP_CHARS to tell select() (via	   n_tty.c:normal_poll() ) that we're not writeable. */	if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )		return 256;	return 0;}static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp){	struct usb_serial *serial = port->serial;	unsigned char room;	int rc = 0;	struct keyspan_pda_private *priv;	down (&port->sem);	MOD_INC_USE_COUNT;	++port->open_count;	if (!port->active) {		port->active = 1; 		/* find out how much room is in the Tx ring */		rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),				     6, /* write_room */				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE				     | USB_DIR_IN,				     0, /* value */				     0, /* index */				     &room,				     1,				     2*HZ);		if (rc < 0) {			dbg(__FUNCTION__" - roomquery failed");			goto error;		}		if (rc == 0) {			dbg(__FUNCTION__" - roomquery returned 0 bytes");			rc = -EIO;			goto error;		}		priv = (struct keyspan_pda_private *)(port->private);		priv->tx_room = room;		priv->tx_throttled = room ? 0 : 1;		/* the normal serial device seems to always turn on DTR and RTS here,		   so do the same */		if (port->tty->termios->c_cflag & CBAUD)			keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );		else			keyspan_pda_set_modem_info(serial, 0);		/*Start reading from the device*/		port->interrupt_in_urb->dev = serial->dev;		rc = usb_submit_urb(port->interrupt_in_urb);		if (rc) {			dbg(__FUNCTION__" - usb_submit_urb(read int) failed");			goto error;		}	}	up (&port->sem);	return rc;error:	--port->open_count;	port->active = 0;	MOD_DEC_USE_COUNT;	up (&port->sem);	return rc;}static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp){	struct usb_serial *serial = port->serial;	down (&port->sem);	--port->open_count;	if (port->open_count <= 0) {		if (serial->dev) {			/* the normal serial device seems to always shut off DTR and RTS now */			if (port->tty->termios->c_cflag & HUPCL)				keyspan_pda_set_modem_info(serial, 0);			/* shutdown our bulk reads and writes */			usb_unlink_urb (port->write_urb);			usb_unlink_urb (port->interrupt_in_urb);		}		port->active = 0;		port->open_count = 0;	}	up (&port->sem);	MOD_DEC_USE_COUNT;}/* download the firmware to a "fake" device (pre-renumeration) */static int keyspan_pda_fake_startup (struct usb_serial *serial){	int response;	const struct ezusb_hex_record *record = NULL;	/* download the firmware here ... */	response = ezusb_set_reset(serial, 1);#ifdef KEYSPAN	if (serial->dev->descriptor.idVendor == KEYSPAN_VENDOR_ID)		record = &keyspan_pda_firmware[0];#endif#ifdef XIRCOM	if ((serial->dev->descriptor.idVendor == XIRCOM_VENDOR_ID) ||	    (serial->dev->descriptor.idVendor == ENTREGRA_VENDOR_ID))		record = &xircom_pgs_firmware[0];#endif	if (record == NULL) {		err(__FUNCTION__": unknown vendor, aborting.");		return -ENODEV;	}	while(record->address != 0xffff) {		response = ezusb_writememory(serial, record->address,					     (unsigned char *)record->data,					     record->data_size, 0xa0);		if (response < 0) {			err("ezusb_writememory failed for Keyspan PDA "			    "firmware (%d %04X %p %d)",			    response, 			    record->address, record->data, record->data_size);			break;		}		record++;	}	/* bring device out of reset. Renumeration will occur in a moment	   and the new device will bind to the real driver */	response = ezusb_set_reset(serial, 0);	/* we want this device to fail to have a driver assigned to it. */	return (1);}static int keyspan_pda_startup (struct usb_serial *serial){	struct keyspan_pda_private *priv;	/* allocate the private data structures for all ports. Well, for all	   one ports. */	priv = serial->port[0].private		= kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL);	if (!priv)		return (1); /* error */	init_waitqueue_head(&serial->port[0].write_wait);	INIT_LIST_HEAD(&priv->wakeup_task.list);	priv->wakeup_task.sync = 0;	priv->wakeup_task.routine = (void *)keyspan_pda_wakeup_write;	priv->wakeup_task.data = (void *)(&serial->port[0]);	INIT_LIST_HEAD(&priv->unthrottle_task.list);	priv->unthrottle_task.sync = 0;	priv->unthrottle_task.routine = (void *)keyspan_pda_request_unthrottle;	priv->unthrottle_task.data = (void *)(serial);	return (0);}static void keyspan_pda_shutdown (struct usb_serial *serial){	dbg (__FUNCTION__);		while (serial->port[0].open_count > 0) {		keyspan_pda_close (&serial->port[0], NULL);	}	kfree(serial->port[0].private);}#ifdef KEYSPANstatic struct usb_serial_device_type keyspan_pda_fake_device = {	name:			"Keyspan PDA - (prerenumeration)",	id_table:		id_table_fake,	needs_interrupt_in:	DONT_CARE,	needs_bulk_in:		DONT_CARE,	needs_bulk_out:		DONT_CARE,	num_interrupt_in:	NUM_DONT_CARE,	num_bulk_in:		NUM_DONT_CARE,	num_bulk_out:		NUM_DONT_CARE,	num_ports:		1,	startup:		keyspan_pda_fake_startup,};#endif#ifdef XIRCOMstatic struct usb_serial_device_type xircom_pgs_fake_device = {        name:                   "Xircom PGS - (prerenumeration)",        id_table:               id_table_fake_xircom,        needs_interrupt_in:     DONT_CARE,        needs_bulk_in:          DONT_CARE,        needs_bulk_out:         DONT_CARE,        num_interrupt_in:       NUM_DONT_CARE,        num_bulk_in:            NUM_DONT_CARE,        num_bulk_out:           NUM_DONT_CARE,        num_ports:              1,        startup:                keyspan_pda_fake_startup,};static struct usb_serial_device_type entregra_pgs_fake_device = {        name:                   "Entregra PGS - (prerenumeration)",        id_table:               id_table_fake_entregra,        needs_interrupt_in:     DONT_CARE,        needs_bulk_in:          DONT_CARE,        needs_bulk_out:         DONT_CARE,        num_interrupt_in:       NUM_DONT_CARE,        num_bulk_in:            NUM_DONT_CARE,        num_bulk_out:           NUM_DONT_CARE,        num_ports:              1,        startup:                keyspan_pda_fake_startup,};#endifstatic struct usb_serial_device_type keyspan_pda_device = {	name:			"Keyspan PDA",	id_table:		id_table_std,	needs_interrupt_in:	MUST_HAVE,	needs_bulk_in:		DONT_CARE,	needs_bulk_out:		MUST_HAVE,	num_interrupt_in:	1,	num_bulk_in:		0,	num_bulk_out:		1,	num_ports:		1,	open:			keyspan_pda_open,	close:			keyspan_pda_close,	write:			keyspan_pda_write,	write_room:		keyspan_pda_write_room,	write_bulk_callback: 	keyspan_pda_write_bulk_callback,	read_int_callback:	keyspan_pda_rx_interrupt,	chars_in_buffer:	keyspan_pda_chars_in_buffer,	throttle:		keyspan_pda_rx_throttle,	unthrottle:		keyspan_pda_rx_unthrottle,	ioctl:			keyspan_pda_ioctl,	set_termios:		keyspan_pda_set_termios,	break_ctl:		keyspan_pda_break_ctl,	startup:		keyspan_pda_startup,	shutdown:		keyspan_pda_shutdown,};static int __init keyspan_pda_init (void){	usb_serial_register (&keyspan_pda_device);#ifdef KEYSPAN	usb_serial_register (&keyspan_pda_fake_device);#endif#ifdef XIRCOM	usb_serial_register (&xircom_pgs_fake_device);	usb_serial_register (&entregra_pgs_fake_device);#endif	info(DRIVER_DESC " " DRIVER_VERSION);	return 0;}static void __exit keyspan_pda_exit (void){	usb_serial_deregister (&keyspan_pda_device);#ifdef KEYSPAN	usb_serial_deregister (&keyspan_pda_fake_device);#endif#ifdef XIRCOM	usb_serial_deregister (&entregra_pgs_fake_device);	usb_serial_deregister (&xircom_pgs_fake_device);#endif}module_init(keyspan_pda_init);module_exit(keyspan_pda_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug enabled or not");

⌨️ 快捷键说明

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