xref: /linux/drivers/usb/serial/empeg.c (revision 18fcac353fdc7cd072b0d24c8667042e675a4c11)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * USB Empeg empeg-car player driver
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *	Copyright (C) 2000, 2001
51da177e4SLinus Torvalds  *	    Gary Brubaker (xavyer@ix.netcom.com)
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	Copyright (C) 1999 - 2001
81da177e4SLinus Torvalds  *	    Greg Kroah-Hartman (greg@kroah.com)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds  *	it under the terms of the GNU General Public License, as published by
121da177e4SLinus Torvalds  *	the Free Software Foundation, version 2.
131da177e4SLinus Torvalds  *
141da177e4SLinus Torvalds  * See Documentation/usb/usb-serial.txt for more information on using this driver
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * (07/16/2001) gb
171da177e4SLinus Torvalds  *	remove unused code in empeg_close() (thanks to Oliver Neukum for pointing this
181da177e4SLinus Torvalds  *	out) and rewrote empeg_set_termios().
191da177e4SLinus Torvalds  *
201da177e4SLinus Torvalds  * (05/30/2001) gkh
211da177e4SLinus Torvalds  *	switched from using spinlock to a semaphore, which fixes lots of problems.
221da177e4SLinus Torvalds  *
231da177e4SLinus Torvalds  * (04/08/2001) gb
241da177e4SLinus Torvalds  *      Identify version on module load.
251da177e4SLinus Torvalds  *
261da177e4SLinus Torvalds  * (01/22/2001) gb
271da177e4SLinus Torvalds  *	Added write_room() and chars_in_buffer() support.
281da177e4SLinus Torvalds  *
291da177e4SLinus Torvalds  * (12/21/2000) gb
301da177e4SLinus Torvalds  *	Moved termio stuff inside the port->active check.
311da177e4SLinus Torvalds  *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
321da177e4SLinus Torvalds  *
331da177e4SLinus Torvalds  * (12/03/2000) gb
341da177e4SLinus Torvalds  *	Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open()
351da177e4SLinus Torvalds  *	This notifies the tty driver that the termios have changed.
361da177e4SLinus Torvalds  *
371da177e4SLinus Torvalds  * (11/13/2000) gb
381da177e4SLinus Torvalds  *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
391da177e4SLinus Torvalds  *	(It only needs to be set once - Doh!)
401da177e4SLinus Torvalds  *
411da177e4SLinus Torvalds  * (11/11/2000) gb
421da177e4SLinus Torvalds  *	Updated to work with id_table structure.
431da177e4SLinus Torvalds  *
441da177e4SLinus Torvalds  * (11/04/2000) gb
451da177e4SLinus Torvalds  *	Forked this from visor.c, and hacked it up to work with an
461da177e4SLinus Torvalds  *	Empeg ltd. empeg-car player.  Constructive criticism welcomed.
471da177e4SLinus Torvalds  *	I would like to say, 'Thank You' to Greg Kroah-Hartman for the
481da177e4SLinus Torvalds  *	use of his code, and for his guidance, advice and patience. :)
491da177e4SLinus Torvalds  *	A 'Thank You' is in order for John Ripley of Empeg ltd for his
501da177e4SLinus Torvalds  *	advice, and patience too.
511da177e4SLinus Torvalds  *
521da177e4SLinus Torvalds  */
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds #include <linux/config.h>
551da177e4SLinus Torvalds #include <linux/kernel.h>
561da177e4SLinus Torvalds #include <linux/errno.h>
571da177e4SLinus Torvalds #include <linux/init.h>
581da177e4SLinus Torvalds #include <linux/slab.h>
591da177e4SLinus Torvalds #include <linux/tty.h>
601da177e4SLinus Torvalds #include <linux/tty_driver.h>
611da177e4SLinus Torvalds #include <linux/tty_flip.h>
621da177e4SLinus Torvalds #include <linux/module.h>
631da177e4SLinus Torvalds #include <linux/spinlock.h>
641da177e4SLinus Torvalds #include <asm/uaccess.h>
651da177e4SLinus Torvalds #include <linux/usb.h>
661da177e4SLinus Torvalds #include "usb-serial.h"
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds static int debug;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /*
711da177e4SLinus Torvalds  * Version Information
721da177e4SLinus Torvalds  */
731da177e4SLinus Torvalds #define DRIVER_VERSION "v1.2"
741da177e4SLinus Torvalds #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
751da177e4SLinus Torvalds #define DRIVER_DESC "USB Empeg Mark I/II Driver"
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds #define EMPEG_VENDOR_ID			0x084f
781da177e4SLinus Torvalds #define EMPEG_PRODUCT_ID		0x0001
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds /* function prototypes for an empeg-car player */
811da177e4SLinus Torvalds static int  empeg_open			(struct usb_serial_port *port, struct file *filp);
821da177e4SLinus Torvalds static void empeg_close			(struct usb_serial_port *port, struct file *filp);
831da177e4SLinus Torvalds static int  empeg_write			(struct usb_serial_port *port,
841da177e4SLinus Torvalds 					const unsigned char *buf,
851da177e4SLinus Torvalds 					int count);
861da177e4SLinus Torvalds static int  empeg_write_room		(struct usb_serial_port *port);
871da177e4SLinus Torvalds static int  empeg_chars_in_buffer	(struct usb_serial_port *port);
881da177e4SLinus Torvalds static void empeg_throttle		(struct usb_serial_port *port);
891da177e4SLinus Torvalds static void empeg_unthrottle		(struct usb_serial_port *port);
901da177e4SLinus Torvalds static int  empeg_startup		(struct usb_serial *serial);
911da177e4SLinus Torvalds static void empeg_shutdown		(struct usb_serial *serial);
921da177e4SLinus Torvalds static int  empeg_ioctl			(struct usb_serial_port *port,
931da177e4SLinus Torvalds 					struct file * file,
941da177e4SLinus Torvalds 					unsigned int cmd,
951da177e4SLinus Torvalds 					unsigned long arg);
961da177e4SLinus Torvalds static void empeg_set_termios		(struct usb_serial_port *port, struct termios *old_termios);
971da177e4SLinus Torvalds static void empeg_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
981da177e4SLinus Torvalds static void empeg_read_bulk_callback	(struct urb *urb, struct pt_regs *regs);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds static struct usb_device_id id_table [] = {
1011da177e4SLinus Torvalds 	{ USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
1021da177e4SLinus Torvalds 	{ }					/* Terminating entry */
1031da177e4SLinus Torvalds };
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds MODULE_DEVICE_TABLE (usb, id_table);
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds static struct usb_driver empeg_driver = {
1081da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
1091da177e4SLinus Torvalds 	.name =		"empeg",
1101da177e4SLinus Torvalds 	.probe =	usb_serial_probe,
1111da177e4SLinus Torvalds 	.disconnect =	usb_serial_disconnect,
1121da177e4SLinus Torvalds 	.id_table =	id_table,
1131da177e4SLinus Torvalds };
1141da177e4SLinus Torvalds 
115ea65370dSGreg Kroah-Hartman static struct usb_serial_driver empeg_device = {
116*18fcac35SGreg Kroah-Hartman 	.driver = {
1171da177e4SLinus Torvalds 		.owner =	THIS_MODULE,
118*18fcac35SGreg Kroah-Hartman 	},
1191da177e4SLinus Torvalds 	.name =			"Empeg",
1201da177e4SLinus Torvalds 	.id_table =		id_table,
1211da177e4SLinus Torvalds 	.num_interrupt_in =	0,
1221da177e4SLinus Torvalds 	.num_bulk_in =		1,
1231da177e4SLinus Torvalds 	.num_bulk_out =		1,
1241da177e4SLinus Torvalds 	.num_ports =		1,
1251da177e4SLinus Torvalds 	.open =			empeg_open,
1261da177e4SLinus Torvalds 	.close =		empeg_close,
1271da177e4SLinus Torvalds 	.throttle =		empeg_throttle,
1281da177e4SLinus Torvalds 	.unthrottle =		empeg_unthrottle,
1291da177e4SLinus Torvalds 	.attach =		empeg_startup,
1301da177e4SLinus Torvalds 	.shutdown =		empeg_shutdown,
1311da177e4SLinus Torvalds 	.ioctl =		empeg_ioctl,
1321da177e4SLinus Torvalds 	.set_termios =		empeg_set_termios,
1331da177e4SLinus Torvalds 	.write =		empeg_write,
1341da177e4SLinus Torvalds 	.write_room =		empeg_write_room,
1351da177e4SLinus Torvalds 	.chars_in_buffer =	empeg_chars_in_buffer,
1361da177e4SLinus Torvalds 	.write_bulk_callback =	empeg_write_bulk_callback,
1371da177e4SLinus Torvalds 	.read_bulk_callback =	empeg_read_bulk_callback,
1381da177e4SLinus Torvalds };
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds #define NUM_URBS			16
1411da177e4SLinus Torvalds #define URB_TRANSFER_BUFFER_SIZE	4096
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds static struct urb	*write_urb_pool[NUM_URBS];
1441da177e4SLinus Torvalds static spinlock_t	write_urb_pool_lock;
1451da177e4SLinus Torvalds static int		bytes_in;
1461da177e4SLinus Torvalds static int		bytes_out;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds /******************************************************************************
1491da177e4SLinus Torvalds  * Empeg specific driver functions
1501da177e4SLinus Torvalds  ******************************************************************************/
1511da177e4SLinus Torvalds static int empeg_open (struct usb_serial_port *port, struct file *filp)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
1541da177e4SLinus Torvalds 	int result = 0;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	/* Force default termio settings */
1591da177e4SLinus Torvalds 	empeg_set_termios (port, NULL) ;
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	bytes_in = 0;
1621da177e4SLinus Torvalds 	bytes_out = 0;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	/* Start reading from the device */
1651da177e4SLinus Torvalds 	usb_fill_bulk_urb(
1661da177e4SLinus Torvalds 		port->read_urb,
1671da177e4SLinus Torvalds 		serial->dev,
1681da177e4SLinus Torvalds 		usb_rcvbulkpipe(serial->dev,
1691da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
1701da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
1711da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
1721da177e4SLinus Torvalds 		empeg_read_bulk_callback,
1731da177e4SLinus Torvalds 		port);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	if (result)
1781da177e4SLinus Torvalds 		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	return result;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds static void empeg_close (struct usb_serial_port *port, struct file * filp)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	/* shutdown our bulk read */
1891da177e4SLinus Torvalds 	usb_kill_urb(port->read_urb);
1901da177e4SLinus Torvalds 	/* Uncomment the following line if you want to see some statistics in your syslog */
1911da177e4SLinus Torvalds 	/* dev_info (&port->dev, "Bytes In = %d  Bytes Out = %d\n", bytes_in, bytes_out); */
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds static int empeg_write (struct usb_serial_port *port, const unsigned char *buf, int count)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
1981da177e4SLinus Torvalds 	struct urb *urb;
1991da177e4SLinus Torvalds 	const unsigned char *current_position = buf;
2001da177e4SLinus Torvalds 	unsigned long flags;
2011da177e4SLinus Torvalds 	int status;
2021da177e4SLinus Torvalds 	int i;
2031da177e4SLinus Torvalds 	int bytes_sent = 0;
2041da177e4SLinus Torvalds 	int transfer_size;
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	while (count > 0) {
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 		/* try to find a free urb in our list of them */
2111da177e4SLinus Torvalds 		urb = NULL;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 		spin_lock_irqsave (&write_urb_pool_lock, flags);
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 		for (i = 0; i < NUM_URBS; ++i) {
2161da177e4SLinus Torvalds 			if (write_urb_pool[i]->status != -EINPROGRESS) {
2171da177e4SLinus Torvalds 				urb = write_urb_pool[i];
2181da177e4SLinus Torvalds 				break;
2191da177e4SLinus Torvalds 			}
2201da177e4SLinus Torvalds 		}
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 		spin_unlock_irqrestore (&write_urb_pool_lock, flags);
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 		if (urb == NULL) {
2251da177e4SLinus Torvalds 			dbg("%s - no more free urbs", __FUNCTION__);
2261da177e4SLinus Torvalds 			goto exit;
2271da177e4SLinus Torvalds 		}
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds 		if (urb->transfer_buffer == NULL) {
2301da177e4SLinus Torvalds 			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
2311da177e4SLinus Torvalds 			if (urb->transfer_buffer == NULL) {
2321da177e4SLinus Torvalds 				dev_err(&port->dev, "%s no more kernel memory...\n", __FUNCTION__);
2331da177e4SLinus Torvalds 				goto exit;
2341da177e4SLinus Torvalds 			}
2351da177e4SLinus Torvalds 		}
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds 		transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 		memcpy (urb->transfer_buffer, current_position, transfer_size);
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 		usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, urb->transfer_buffer);
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 		/* build up our urb */
2441da177e4SLinus Torvalds 		usb_fill_bulk_urb (
2451da177e4SLinus Torvalds 			urb,
2461da177e4SLinus Torvalds 			serial->dev,
2471da177e4SLinus Torvalds 			usb_sndbulkpipe(serial->dev,
2481da177e4SLinus Torvalds 				port->bulk_out_endpointAddress),
2491da177e4SLinus Torvalds 			urb->transfer_buffer,
2501da177e4SLinus Torvalds 			transfer_size,
2511da177e4SLinus Torvalds 			empeg_write_bulk_callback,
2521da177e4SLinus Torvalds 			port);
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 		/* send it down the pipe */
2551da177e4SLinus Torvalds 		status = usb_submit_urb(urb, GFP_ATOMIC);
2561da177e4SLinus Torvalds 		if (status) {
2571da177e4SLinus Torvalds 			dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __FUNCTION__, status);
2581da177e4SLinus Torvalds 			bytes_sent = status;
2591da177e4SLinus Torvalds 			break;
2601da177e4SLinus Torvalds 		}
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 		current_position += transfer_size;
2631da177e4SLinus Torvalds 		bytes_sent += transfer_size;
2641da177e4SLinus Torvalds 		count -= transfer_size;
2651da177e4SLinus Torvalds 		bytes_out += transfer_size;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	}
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds exit:
2701da177e4SLinus Torvalds 	return bytes_sent;
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds static int empeg_write_room (struct usb_serial_port *port)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	unsigned long flags;
2781da177e4SLinus Torvalds 	int i;
2791da177e4SLinus Torvalds 	int room = 0;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	/* tally up the number of bytes available */
2861da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
2871da177e4SLinus Torvalds 		if (write_urb_pool[i]->status != -EINPROGRESS) {
2881da177e4SLinus Torvalds 			room += URB_TRANSFER_BUFFER_SIZE;
2891da177e4SLinus Torvalds 		}
2901da177e4SLinus Torvalds 	}
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	dbg("%s - returns %d", __FUNCTION__, room);
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 	return (room);
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds }
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds static int empeg_chars_in_buffer (struct usb_serial_port *port)
3021da177e4SLinus Torvalds {
3031da177e4SLinus Torvalds 	unsigned long flags;
3041da177e4SLinus Torvalds 	int i;
3051da177e4SLinus Torvalds 	int chars = 0;
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	/* tally up the number of bytes waiting */
3121da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
3131da177e4SLinus Torvalds 		if (write_urb_pool[i]->status == -EINPROGRESS) {
3141da177e4SLinus Torvalds 			chars += URB_TRANSFER_BUFFER_SIZE;
3151da177e4SLinus Torvalds 		}
3161da177e4SLinus Torvalds 	}
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	dbg("%s - returns %d", __FUNCTION__, chars);
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	return (chars);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
3281da177e4SLinus Torvalds {
3291da177e4SLinus Torvalds 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	if (urb->status) {
3341da177e4SLinus Torvalds 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
3351da177e4SLinus Torvalds 		return;
3361da177e4SLinus Torvalds 	}
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	schedule_work(&port->work);
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
3451da177e4SLinus Torvalds 	struct tty_struct *tty;
3461da177e4SLinus Torvalds 	unsigned char *data = urb->transfer_buffer;
3471da177e4SLinus Torvalds 	int i;
3481da177e4SLinus Torvalds 	int result;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	if (urb->status) {
3531da177e4SLinus Torvalds 		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
3541da177e4SLinus Torvalds 		return;
3551da177e4SLinus Torvalds 	}
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	tty = port->tty;
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds 	if (urb->actual_length) {
3621da177e4SLinus Torvalds 		for (i = 0; i < urb->actual_length ; ++i) {
3631da177e4SLinus Torvalds 			/* gb - 2000/11/13
3641da177e4SLinus Torvalds 			 * If we insert too many characters we'll overflow the buffer.
3651da177e4SLinus Torvalds 			 * This means we'll lose bytes - Decidedly bad.
3661da177e4SLinus Torvalds 			 */
3671da177e4SLinus Torvalds 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
3681da177e4SLinus Torvalds 				tty_flip_buffer_push(tty);
3691da177e4SLinus Torvalds 				}
3701da177e4SLinus Torvalds 			tty_insert_flip_char(tty, data[i], 0);
3711da177e4SLinus Torvalds 		}
3721da177e4SLinus Torvalds 		/* gb - 2000/11/13
3731da177e4SLinus Torvalds 		 * Goes straight through instead of scheduling - if tty->low_latency is set.
3741da177e4SLinus Torvalds 		 */
3751da177e4SLinus Torvalds 		tty_flip_buffer_push(tty);
3761da177e4SLinus Torvalds 		bytes_in += urb->actual_length;
3771da177e4SLinus Torvalds 	}
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	/* Continue trying to always read  */
3801da177e4SLinus Torvalds 	usb_fill_bulk_urb(
3811da177e4SLinus Torvalds 		port->read_urb,
3821da177e4SLinus Torvalds 		port->serial->dev,
3831da177e4SLinus Torvalds 		usb_rcvbulkpipe(port->serial->dev,
3841da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
3851da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
3861da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
3871da177e4SLinus Torvalds 		empeg_read_bulk_callback,
3881da177e4SLinus Torvalds 		port);
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	if (result)
3931da177e4SLinus Torvalds 		dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	return;
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds static void empeg_throttle (struct usb_serial_port *port)
4011da177e4SLinus Torvalds {
4021da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4031da177e4SLinus Torvalds 	usb_kill_urb(port->read_urb);
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds static void empeg_unthrottle (struct usb_serial_port *port)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	int result;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	port->read_urb->dev = port->serial->dev;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	if (result)
4181da177e4SLinus Torvalds 		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
4191da177e4SLinus Torvalds 
4201da177e4SLinus Torvalds 	return;
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds static int  empeg_startup (struct usb_serial *serial)
4251da177e4SLinus Torvalds {
4261da177e4SLinus Torvalds 	int r;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	dbg("%s", __FUNCTION__);
4291da177e4SLinus Torvalds 
4301da177e4SLinus Torvalds 	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
4311da177e4SLinus Torvalds 		err("active config #%d != 1 ??",
4321da177e4SLinus Torvalds 			serial->dev->actconfig->desc.bConfigurationValue);
4331da177e4SLinus Torvalds 		return -ENODEV;
4341da177e4SLinus Torvalds 	}
4351da177e4SLinus Torvalds 	dbg("%s - reset config", __FUNCTION__);
4361da177e4SLinus Torvalds 	r = usb_reset_configuration (serial->dev);
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds 	/* continue on with initialization */
4391da177e4SLinus Torvalds 	return r;
4401da177e4SLinus Torvalds 
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds static void empeg_shutdown (struct usb_serial *serial)
4451da177e4SLinus Torvalds {
4461da177e4SLinus Torvalds 	dbg ("%s", __FUNCTION__);
4471da177e4SLinus Torvalds }
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
4531da177e4SLinus Torvalds 
4541da177e4SLinus Torvalds 	return -ENOIOCTLCMD;
4551da177e4SLinus Torvalds }
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
4591da177e4SLinus Torvalds {
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4621da177e4SLinus Torvalds 
4631da177e4SLinus Torvalds 	if ((!port->tty) || (!port->tty->termios)) {
4641da177e4SLinus Torvalds 		dbg("%s - no tty structures", __FUNCTION__);
4651da177e4SLinus Torvalds 		return;
4661da177e4SLinus Torvalds 	}
4671da177e4SLinus Torvalds 
4681da177e4SLinus Torvalds 	/*
4691da177e4SLinus Torvalds          * The empeg-car player wants these particular tty settings.
4701da177e4SLinus Torvalds          * You could, for example, change the baud rate, however the
4711da177e4SLinus Torvalds          * player only supports 115200 (currently), so there is really
4721da177e4SLinus Torvalds          * no point in support for changes to the tty settings.
4731da177e4SLinus Torvalds          * (at least for now)
4741da177e4SLinus Torvalds          *
4751da177e4SLinus Torvalds          * The default requirements for this device are:
4761da177e4SLinus Torvalds          */
4771da177e4SLinus Torvalds 	port->tty->termios->c_iflag
4781da177e4SLinus Torvalds 		&= ~(IGNBRK	/* disable ignore break */
4791da177e4SLinus Torvalds 		| BRKINT	/* disable break causes interrupt */
4801da177e4SLinus Torvalds 		| PARMRK	/* disable mark parity errors */
4811da177e4SLinus Torvalds 		| ISTRIP	/* disable clear high bit of input characters */
4821da177e4SLinus Torvalds 		| INLCR		/* disable translate NL to CR */
4831da177e4SLinus Torvalds 		| IGNCR		/* disable ignore CR */
4841da177e4SLinus Torvalds 		| ICRNL		/* disable translate CR to NL */
4851da177e4SLinus Torvalds 		| IXON);	/* disable enable XON/XOFF flow control */
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	port->tty->termios->c_oflag
4881da177e4SLinus Torvalds 		&= ~OPOST;	/* disable postprocess output characters */
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	port->tty->termios->c_lflag
4911da177e4SLinus Torvalds 		&= ~(ECHO	/* disable echo input characters */
4921da177e4SLinus Torvalds 		| ECHONL	/* disable echo new line */
4931da177e4SLinus Torvalds 		| ICANON	/* disable erase, kill, werase, and rprnt special characters */
4941da177e4SLinus Torvalds 		| ISIG		/* disable interrupt, quit, and suspend special characters */
4951da177e4SLinus Torvalds 		| IEXTEN);	/* disable non-POSIX special characters */
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 	port->tty->termios->c_cflag
4981da177e4SLinus Torvalds 		&= ~(CSIZE	/* no size */
4991da177e4SLinus Torvalds 		| PARENB	/* disable parity bit */
5001da177e4SLinus Torvalds 		| CBAUD);	/* clear current baud rate */
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	port->tty->termios->c_cflag
5031da177e4SLinus Torvalds 		|= (CS8		/* character size 8 bits */
5041da177e4SLinus Torvalds 		| B115200);	/* baud rate 115200 */
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 	/*
5071da177e4SLinus Torvalds 	 * Force low_latency on; otherwise the pushes are scheduled;
5081da177e4SLinus Torvalds 	 * this is bad as it opens up the possibility of dropping bytes
5091da177e4SLinus Torvalds 	 * on the floor.  We don't want to drop bytes on the floor. :)
5101da177e4SLinus Torvalds 	 */
5111da177e4SLinus Torvalds 	port->tty->low_latency = 1;
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	return;
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds 
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds static int __init empeg_init (void)
5181da177e4SLinus Torvalds {
5191da177e4SLinus Torvalds 	struct urb *urb;
5201da177e4SLinus Torvalds 	int i, retval;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	/* create our write urb pool and transfer buffers */
5231da177e4SLinus Torvalds 	spin_lock_init (&write_urb_pool_lock);
5241da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5251da177e4SLinus Torvalds 		urb = usb_alloc_urb(0, GFP_KERNEL);
5261da177e4SLinus Torvalds 		write_urb_pool[i] = urb;
5271da177e4SLinus Torvalds 		if (urb == NULL) {
5281da177e4SLinus Torvalds 			err("No more urbs???");
5291da177e4SLinus Torvalds 			continue;
5301da177e4SLinus Torvalds 		}
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
5331da177e4SLinus Torvalds 		if (!urb->transfer_buffer) {
5341da177e4SLinus Torvalds 			err("%s - out of memory for urb buffers.",
5351da177e4SLinus Torvalds 			    __FUNCTION__);
5361da177e4SLinus Torvalds 			continue;
5371da177e4SLinus Torvalds 		}
5381da177e4SLinus Torvalds 	}
5391da177e4SLinus Torvalds 
5401da177e4SLinus Torvalds 	retval = usb_serial_register(&empeg_device);
5411da177e4SLinus Torvalds 	if (retval)
5421da177e4SLinus Torvalds 		goto failed_usb_serial_register;
5431da177e4SLinus Torvalds 	retval = usb_register(&empeg_driver);
5441da177e4SLinus Torvalds 	if (retval)
5451da177e4SLinus Torvalds 		goto failed_usb_register;
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 	info(DRIVER_VERSION ":" DRIVER_DESC);
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	return 0;
5501da177e4SLinus Torvalds failed_usb_register:
5511da177e4SLinus Torvalds 	usb_serial_deregister(&empeg_device);
5521da177e4SLinus Torvalds failed_usb_serial_register:
5531da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5541da177e4SLinus Torvalds 		if (write_urb_pool[i]) {
5551da177e4SLinus Torvalds 			kfree(write_urb_pool[i]->transfer_buffer);
5561da177e4SLinus Torvalds 			usb_free_urb(write_urb_pool[i]);
5571da177e4SLinus Torvalds 		}
5581da177e4SLinus Torvalds 	}
5591da177e4SLinus Torvalds 	return retval;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds static void __exit empeg_exit (void)
5641da177e4SLinus Torvalds {
5651da177e4SLinus Torvalds 	int i;
5661da177e4SLinus Torvalds 	unsigned long flags;
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 	usb_deregister(&empeg_driver);
5691da177e4SLinus Torvalds 	usb_serial_deregister (&empeg_device);
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
5721da177e4SLinus Torvalds 
5731da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5741da177e4SLinus Torvalds 		if (write_urb_pool[i]) {
5751da177e4SLinus Torvalds 			/* FIXME - uncomment the following usb_kill_urb call when
5761da177e4SLinus Torvalds 			 * the host controllers get fixed to set urb->dev = NULL after
5771da177e4SLinus Torvalds 			 * the urb is finished.  Otherwise this call oopses. */
5781da177e4SLinus Torvalds 			/* usb_kill_urb(write_urb_pool[i]); */
5791da177e4SLinus Torvalds 			kfree(write_urb_pool[i]->transfer_buffer);
5801da177e4SLinus Torvalds 			usb_free_urb (write_urb_pool[i]);
5811da177e4SLinus Torvalds 		}
5821da177e4SLinus Torvalds 	}
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
5851da177e4SLinus Torvalds }
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds module_init(empeg_init);
5891da177e4SLinus Torvalds module_exit(empeg_exit);
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds MODULE_AUTHOR( DRIVER_AUTHOR );
5921da177e4SLinus Torvalds MODULE_DESCRIPTION( DRIVER_DESC );
5931da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds module_param(debug, bool, S_IRUGO | S_IWUSR);
5961da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Debug enabled or not");
597