xref: /linux/drivers/usb/serial/empeg.c (revision c197a8db59daf06dc5e77acd5a9681329cb22458)
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  *
1493c46795SAlan Cox  * See Documentation/usb/usb-serial.txt for more information on using this
1593c46795SAlan Cox  * driver
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * (07/16/2001) gb
1893c46795SAlan Cox  *	remove unused code in empeg_close() (thanks to Oliver Neukum for
1993c46795SAlan Cox  *	pointing this out) and rewrote empeg_set_termios().
201da177e4SLinus Torvalds  *
211da177e4SLinus Torvalds  * (05/30/2001) gkh
2293c46795SAlan Cox  *	switched from using spinlock to a semaphore, which fixes lots of
2393c46795SAlan Cox  * problems.
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * (04/08/2001) gb
261da177e4SLinus Torvalds  *      Identify version on module load.
271da177e4SLinus Torvalds  *
281da177e4SLinus Torvalds  * (01/22/2001) gb
291da177e4SLinus Torvalds  *	Added write_room() and chars_in_buffer() support.
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  * (12/21/2000) gb
321da177e4SLinus Torvalds  *	Moved termio stuff inside the port->active check.
331da177e4SLinus Torvalds  *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  * (12/03/2000) gb
364a90f09bSAlan Cox  *	Added tty->ldisc.set_termios(port, tty, NULL) to empeg_open().
374a90f09bSAlan Cox  *	This notifies the tty driver that the termios have changed.
381da177e4SLinus Torvalds  *
391da177e4SLinus Torvalds  * (11/13/2000) gb
4093c46795SAlan Cox  *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to
4193c46795SAlan Cox  *	empeg_open() (It only needs to be set once - Doh!)
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * (11/11/2000) gb
441da177e4SLinus Torvalds  *	Updated to work with id_table structure.
451da177e4SLinus Torvalds  *
461da177e4SLinus Torvalds  * (11/04/2000) gb
471da177e4SLinus Torvalds  *	Forked this from visor.c, and hacked it up to work with an
481da177e4SLinus Torvalds  *	Empeg ltd. empeg-car player.  Constructive criticism welcomed.
491da177e4SLinus Torvalds  *	I would like to say, 'Thank You' to Greg Kroah-Hartman for the
501da177e4SLinus Torvalds  *	use of his code, and for his guidance, advice and patience. :)
511da177e4SLinus Torvalds  *	A 'Thank You' is in order for John Ripley of Empeg ltd for his
521da177e4SLinus Torvalds  *	advice, and patience too.
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  */
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #include <linux/kernel.h>
571da177e4SLinus Torvalds #include <linux/errno.h>
581da177e4SLinus Torvalds #include <linux/init.h>
591da177e4SLinus Torvalds #include <linux/slab.h>
601da177e4SLinus Torvalds #include <linux/tty.h>
611da177e4SLinus Torvalds #include <linux/tty_driver.h>
621da177e4SLinus Torvalds #include <linux/tty_flip.h>
631da177e4SLinus Torvalds #include <linux/module.h>
641da177e4SLinus Torvalds #include <linux/spinlock.h>
6593c46795SAlan Cox #include <linux/uaccess.h>
661da177e4SLinus Torvalds #include <linux/usb.h>
67a969888cSGreg Kroah-Hartman #include <linux/usb/serial.h>
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static int debug;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /*
721da177e4SLinus Torvalds  * Version Information
731da177e4SLinus Torvalds  */
741da177e4SLinus Torvalds #define DRIVER_VERSION "v1.2"
751da177e4SLinus Torvalds #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
761da177e4SLinus Torvalds #define DRIVER_DESC "USB Empeg Mark I/II Driver"
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds #define EMPEG_VENDOR_ID			0x084f
791da177e4SLinus Torvalds #define EMPEG_PRODUCT_ID		0x0001
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds /* function prototypes for an empeg-car player */
8293c46795SAlan Cox static int  empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
8393c46795SAlan Cox 						struct file *filp);
8493c46795SAlan Cox static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
8593c46795SAlan Cox 						struct file *filp);
8695da310eSAlan Cox static int  empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
871da177e4SLinus Torvalds 						const unsigned char *buf,
881da177e4SLinus Torvalds 						int count);
8995da310eSAlan Cox static int  empeg_write_room(struct tty_struct *tty);
9095da310eSAlan Cox static int  empeg_chars_in_buffer(struct tty_struct *tty);
9195da310eSAlan Cox static void empeg_throttle(struct tty_struct *tty);
9295da310eSAlan Cox static void empeg_unthrottle(struct tty_struct *tty);
931da177e4SLinus Torvalds static int  empeg_startup(struct usb_serial *serial);
941da177e4SLinus Torvalds static void empeg_shutdown(struct usb_serial *serial);
9593c46795SAlan Cox static void empeg_set_termios(struct tty_struct *tty,
9693c46795SAlan Cox 		struct usb_serial_port *port, struct ktermios *old_termios);
977d12e780SDavid Howells static void empeg_write_bulk_callback(struct urb *urb);
987d12e780SDavid Howells static void empeg_read_bulk_callback(struct urb *urb);
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 	.name =		"empeg",
1091da177e4SLinus Torvalds 	.probe =	usb_serial_probe,
1101da177e4SLinus Torvalds 	.disconnect =	usb_serial_disconnect,
1111da177e4SLinus Torvalds 	.id_table =	id_table,
112ba9dc657SGreg Kroah-Hartman 	.no_dynamic_id = 	1,
1131da177e4SLinus Torvalds };
1141da177e4SLinus Torvalds 
115ea65370dSGreg Kroah-Hartman static struct usb_serial_driver empeg_device = {
11618fcac35SGreg Kroah-Hartman 	.driver = {
1171da177e4SLinus Torvalds 		.owner =	THIS_MODULE,
118269bda1cSGreg Kroah-Hartman 		.name =		"empeg",
11918fcac35SGreg Kroah-Hartman 	},
1201da177e4SLinus Torvalds 	.id_table =		id_table,
121d9b1b787SJohannes Hölzl 	.usb_driver = 		&empeg_driver,
1221da177e4SLinus Torvalds 	.num_ports =		1,
1231da177e4SLinus Torvalds 	.open =			empeg_open,
1241da177e4SLinus Torvalds 	.close =		empeg_close,
1251da177e4SLinus Torvalds 	.throttle =		empeg_throttle,
1261da177e4SLinus Torvalds 	.unthrottle =		empeg_unthrottle,
1271da177e4SLinus Torvalds 	.attach =		empeg_startup,
1281da177e4SLinus Torvalds 	.shutdown =		empeg_shutdown,
1291da177e4SLinus Torvalds 	.set_termios =		empeg_set_termios,
1301da177e4SLinus Torvalds 	.write =		empeg_write,
1311da177e4SLinus Torvalds 	.write_room =		empeg_write_room,
1321da177e4SLinus Torvalds 	.chars_in_buffer =	empeg_chars_in_buffer,
1331da177e4SLinus Torvalds 	.write_bulk_callback =	empeg_write_bulk_callback,
1341da177e4SLinus Torvalds 	.read_bulk_callback =	empeg_read_bulk_callback,
1351da177e4SLinus Torvalds };
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds #define NUM_URBS			16
1381da177e4SLinus Torvalds #define URB_TRANSFER_BUFFER_SIZE	4096
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds static struct urb	*write_urb_pool[NUM_URBS];
1411da177e4SLinus Torvalds static spinlock_t	write_urb_pool_lock;
1421da177e4SLinus Torvalds static int		bytes_in;
1431da177e4SLinus Torvalds static int		bytes_out;
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds /******************************************************************************
1461da177e4SLinus Torvalds  * Empeg specific driver functions
1471da177e4SLinus Torvalds  ******************************************************************************/
14895da310eSAlan Cox static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
14995da310eSAlan Cox 				struct file *filp)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
1521da177e4SLinus Torvalds 	int result = 0;
1531da177e4SLinus Torvalds 
154441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	/* Force default termio settings */
15795da310eSAlan Cox 	empeg_set_termios(tty, port, NULL) ;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	bytes_in = 0;
1601da177e4SLinus Torvalds 	bytes_out = 0;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	/* Start reading from the device */
1631da177e4SLinus Torvalds 	usb_fill_bulk_urb(
1641da177e4SLinus Torvalds 		port->read_urb,
1651da177e4SLinus Torvalds 		serial->dev,
1661da177e4SLinus Torvalds 		usb_rcvbulkpipe(serial->dev,
1671da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
1681da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
1691da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
1701da177e4SLinus Torvalds 		empeg_read_bulk_callback,
1711da177e4SLinus Torvalds 		port);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	if (result)
17693c46795SAlan Cox 		dev_err(&port->dev,
17793c46795SAlan Cox 			"%s - failed submitting read urb, error %d\n",
17893c46795SAlan Cox 							__func__, result);
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	return result;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 
18495da310eSAlan Cox static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
18595da310eSAlan Cox 				struct file *filp)
1861da177e4SLinus Torvalds {
187441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 	/* shutdown our bulk read */
1901da177e4SLinus Torvalds 	usb_kill_urb(port->read_urb);
1911da177e4SLinus Torvalds 	/* Uncomment the following line if you want to see some statistics in your syslog */
1921da177e4SLinus Torvalds 	/* dev_info (&port->dev, "Bytes In = %d  Bytes Out = %d\n", bytes_in, bytes_out); */
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 
19693c46795SAlan Cox static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
19793c46795SAlan Cox 					const unsigned char *buf, int count)
1981da177e4SLinus Torvalds {
1991da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
2001da177e4SLinus Torvalds 	struct urb *urb;
2011da177e4SLinus Torvalds 	const unsigned char *current_position = buf;
2021da177e4SLinus Torvalds 	unsigned long flags;
2031da177e4SLinus Torvalds 	int status;
2041da177e4SLinus Torvalds 	int i;
2051da177e4SLinus Torvalds 	int bytes_sent = 0;
2061da177e4SLinus Torvalds 	int transfer_size;
2071da177e4SLinus Torvalds 
208441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	while (count > 0) {
2111da177e4SLinus Torvalds 		/* try to find a free urb in our list of them */
2121da177e4SLinus Torvalds 		urb = NULL;
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 		spin_lock_irqsave(&write_urb_pool_lock, flags);
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 		for (i = 0; i < NUM_URBS; ++i) {
2171da177e4SLinus Torvalds 			if (write_urb_pool[i]->status != -EINPROGRESS) {
2181da177e4SLinus Torvalds 				urb = write_urb_pool[i];
2191da177e4SLinus Torvalds 				break;
2201da177e4SLinus Torvalds 			}
2211da177e4SLinus Torvalds 		}
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 		spin_unlock_irqrestore(&write_urb_pool_lock, flags);
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 		if (urb == NULL) {
226441b62c1SHarvey Harrison 			dbg("%s - no more free urbs", __func__);
2271da177e4SLinus Torvalds 			goto exit;
2281da177e4SLinus Torvalds 		}
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 		if (urb->transfer_buffer == NULL) {
2311da177e4SLinus Torvalds 			urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC);
2321da177e4SLinus Torvalds 			if (urb->transfer_buffer == NULL) {
23393c46795SAlan Cox 				dev_err(&port->dev,
23493c46795SAlan Cox 					"%s no more kernel memory...\n",
23593c46795SAlan Cox 								__func__);
2361da177e4SLinus Torvalds 				goto exit;
2371da177e4SLinus Torvalds 			}
2381da177e4SLinus Torvalds 		}
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 		transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 		memcpy(urb->transfer_buffer, current_position, transfer_size);
2431da177e4SLinus Torvalds 
244441b62c1SHarvey Harrison 		usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, urb->transfer_buffer);
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds 		/* build up our urb */
2471da177e4SLinus Torvalds 		usb_fill_bulk_urb(
2481da177e4SLinus Torvalds 			urb,
2491da177e4SLinus Torvalds 			serial->dev,
2501da177e4SLinus Torvalds 			usb_sndbulkpipe(serial->dev,
2511da177e4SLinus Torvalds 					port->bulk_out_endpointAddress),
2521da177e4SLinus Torvalds 			urb->transfer_buffer,
2531da177e4SLinus Torvalds 			transfer_size,
2541da177e4SLinus Torvalds 			empeg_write_bulk_callback,
2551da177e4SLinus Torvalds 			port);
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 		/* send it down the pipe */
2581da177e4SLinus Torvalds 		status = usb_submit_urb(urb, GFP_ATOMIC);
2591da177e4SLinus Torvalds 		if (status) {
260441b62c1SHarvey Harrison 			dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status);
2611da177e4SLinus Torvalds 			bytes_sent = status;
2621da177e4SLinus Torvalds 			break;
2631da177e4SLinus Torvalds 		}
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 		current_position += transfer_size;
2661da177e4SLinus Torvalds 		bytes_sent += transfer_size;
2671da177e4SLinus Torvalds 		count -= transfer_size;
2681da177e4SLinus Torvalds 		bytes_out += transfer_size;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	}
2711da177e4SLinus Torvalds exit:
2721da177e4SLinus Torvalds 	return bytes_sent;
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 
27695da310eSAlan Cox static int empeg_write_room(struct tty_struct *tty)
2771da177e4SLinus Torvalds {
27895da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
2791da177e4SLinus Torvalds 	unsigned long flags;
2801da177e4SLinus Torvalds 	int i;
2811da177e4SLinus Torvalds 	int room = 0;
2821da177e4SLinus Torvalds 
283441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	spin_lock_irqsave(&write_urb_pool_lock, flags);
2861da177e4SLinus Torvalds 	/* tally up the number of bytes available */
2871da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
28893c46795SAlan Cox 		if (write_urb_pool[i]->status != -EINPROGRESS)
2891da177e4SLinus Torvalds 			room += URB_TRANSFER_BUFFER_SIZE;
2901da177e4SLinus Torvalds 	}
2911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
292441b62c1SHarvey Harrison 	dbg("%s - returns %d", __func__, room);
29395da310eSAlan Cox 	return room;
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 
29895da310eSAlan Cox static int empeg_chars_in_buffer(struct tty_struct *tty)
2991da177e4SLinus Torvalds {
30095da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
3011da177e4SLinus Torvalds 	unsigned long flags;
3021da177e4SLinus Torvalds 	int i;
3031da177e4SLinus Torvalds 	int chars = 0;
3041da177e4SLinus Torvalds 
305441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	spin_lock_irqsave(&write_urb_pool_lock, flags);
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds 	/* tally up the number of bytes waiting */
3101da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
31193c46795SAlan Cox 		if (write_urb_pool[i]->status == -EINPROGRESS)
3121da177e4SLinus Torvalds 			chars += URB_TRANSFER_BUFFER_SIZE;
3131da177e4SLinus Torvalds 	}
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
316441b62c1SHarvey Harrison 	dbg("%s - returns %d", __func__, chars);
31793c46795SAlan Cox 	return chars;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 
3217d12e780SDavid Howells static void empeg_write_bulk_callback(struct urb *urb)
3221da177e4SLinus Torvalds {
323335202f4SGreg Kroah-Hartman 	struct usb_serial_port *port = urb->context;
324335202f4SGreg Kroah-Hartman 	int status = urb->status;
3251da177e4SLinus Torvalds 
326441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
3271da177e4SLinus Torvalds 
328335202f4SGreg Kroah-Hartman 	if (status) {
329335202f4SGreg Kroah-Hartman 		dbg("%s - nonzero write bulk status received: %d",
330441b62c1SHarvey Harrison 		    __func__, status);
3311da177e4SLinus Torvalds 		return;
3321da177e4SLinus Torvalds 	}
3331da177e4SLinus Torvalds 
334cf2c7481SPete Zaitcev 	usb_serial_port_softint(port);
3351da177e4SLinus Torvalds }
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 
3387d12e780SDavid Howells static void empeg_read_bulk_callback(struct urb *urb)
3391da177e4SLinus Torvalds {
340cdc97792SMing Lei 	struct usb_serial_port *port = urb->context;
3411da177e4SLinus Torvalds 	struct tty_struct *tty;
3421da177e4SLinus Torvalds 	unsigned char *data = urb->transfer_buffer;
3431da177e4SLinus Torvalds 	int result;
344335202f4SGreg Kroah-Hartman 	int status = urb->status;
3451da177e4SLinus Torvalds 
346441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
3471da177e4SLinus Torvalds 
348335202f4SGreg Kroah-Hartman 	if (status) {
349335202f4SGreg Kroah-Hartman 		dbg("%s - nonzero read bulk status received: %d",
350441b62c1SHarvey Harrison 		    __func__, status);
3511da177e4SLinus Torvalds 		return;
3521da177e4SLinus Torvalds 	}
3531da177e4SLinus Torvalds 
35493c46795SAlan Cox 	usb_serial_debug_data(debug, &port->dev, __func__,
35593c46795SAlan Cox 						urb->actual_length, data);
3564a90f09bSAlan Cox 	tty = tty_port_tty_get(&port->port);
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	if (urb->actual_length) {
35933f0f88fSAlan Cox 		tty_buffer_request_room(tty, urb->actual_length);
36033f0f88fSAlan Cox 		tty_insert_flip_string(tty, data, urb->actual_length);
3611da177e4SLinus Torvalds 		tty_flip_buffer_push(tty);
3621da177e4SLinus Torvalds 		bytes_in += urb->actual_length;
3631da177e4SLinus Torvalds 	}
3644a90f09bSAlan Cox 	tty_kref_put(tty);
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	/* Continue trying to always read  */
3671da177e4SLinus Torvalds 	usb_fill_bulk_urb(
3681da177e4SLinus Torvalds 		port->read_urb,
3691da177e4SLinus Torvalds 		port->serial->dev,
3701da177e4SLinus Torvalds 		usb_rcvbulkpipe(port->serial->dev,
3711da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
3721da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
3731da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
3741da177e4SLinus Torvalds 		empeg_read_bulk_callback,
3751da177e4SLinus Torvalds 		port);
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	if (result)
38093c46795SAlan Cox 		dev_err(&urb->dev->dev,
38193c46795SAlan Cox 			"%s - failed resubmitting read urb, error %d\n",
38293c46795SAlan Cox 							__func__, result);
3831da177e4SLinus Torvalds 
3841da177e4SLinus Torvalds 	return;
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds }
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 
38995da310eSAlan Cox static void empeg_throttle(struct tty_struct *tty)
3901da177e4SLinus Torvalds {
39195da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
392441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
3931da177e4SLinus Torvalds 	usb_kill_urb(port->read_urb);
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 
39795da310eSAlan Cox static void empeg_unthrottle(struct tty_struct *tty)
3981da177e4SLinus Torvalds {
39995da310eSAlan Cox 	struct usb_serial_port *port = tty->driver_data;
4001da177e4SLinus Torvalds 	int result;
401441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 	port->read_urb->dev = port->serial->dev;
4041da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
4051da177e4SLinus Torvalds 	if (result)
40693c46795SAlan Cox 		dev_err(&port->dev,
40793c46795SAlan Cox 			"%s - failed submitting read urb, error %d\n",
40893c46795SAlan Cox 							__func__, result);
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds static int  empeg_startup(struct usb_serial *serial)
4131da177e4SLinus Torvalds {
4141da177e4SLinus Torvalds 	int r;
4151da177e4SLinus Torvalds 
416441b62c1SHarvey Harrison 	dbg("%s", __func__);
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
4191da177e4SLinus Torvalds 		err("active config #%d != 1 ??",
4201da177e4SLinus Torvalds 			serial->dev->actconfig->desc.bConfigurationValue);
4211da177e4SLinus Torvalds 		return -ENODEV;
4221da177e4SLinus Torvalds 	}
423441b62c1SHarvey Harrison 	dbg("%s - reset config", __func__);
4241da177e4SLinus Torvalds 	r = usb_reset_configuration(serial->dev);
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	/* continue on with initialization */
4271da177e4SLinus Torvalds 	return r;
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds static void empeg_shutdown(struct usb_serial *serial)
4331da177e4SLinus Torvalds {
434441b62c1SHarvey Harrison 	dbg("%s", __func__);
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 
43895da310eSAlan Cox static void empeg_set_termios(struct tty_struct *tty,
43995da310eSAlan Cox 		struct usb_serial_port *port, struct ktermios *old_termios)
4401da177e4SLinus Torvalds {
44195da310eSAlan Cox 	struct ktermios *termios = tty->termios;
442441b62c1SHarvey Harrison 	dbg("%s - port %d", __func__, port->number);
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 	/*
4451da177e4SLinus Torvalds 	 * The empeg-car player wants these particular tty settings.
4461da177e4SLinus Torvalds 	 * You could, for example, change the baud rate, however the
4471da177e4SLinus Torvalds 	 * player only supports 115200 (currently), so there is really
4481da177e4SLinus Torvalds 	 * no point in support for changes to the tty settings.
4491da177e4SLinus Torvalds 	 * (at least for now)
4501da177e4SLinus Torvalds 	 *
4511da177e4SLinus Torvalds 	 * The default requirements for this device are:
4521da177e4SLinus Torvalds 	 */
453998e8638SAlan Cox 	termios->c_iflag
4541da177e4SLinus Torvalds 		&= ~(IGNBRK	/* disable ignore break */
4551da177e4SLinus Torvalds 		| BRKINT	/* disable break causes interrupt */
4561da177e4SLinus Torvalds 		| PARMRK	/* disable mark parity errors */
4571da177e4SLinus Torvalds 		| ISTRIP	/* disable clear high bit of input characters */
4581da177e4SLinus Torvalds 		| INLCR		/* disable translate NL to CR */
4591da177e4SLinus Torvalds 		| IGNCR		/* disable ignore CR */
4601da177e4SLinus Torvalds 		| ICRNL		/* disable translate CR to NL */
4611da177e4SLinus Torvalds 		| IXON);	/* disable enable XON/XOFF flow control */
4621da177e4SLinus Torvalds 
463998e8638SAlan Cox 	termios->c_oflag
4641da177e4SLinus Torvalds 		&= ~OPOST;	/* disable postprocess output characters */
4651da177e4SLinus Torvalds 
466998e8638SAlan Cox 	termios->c_lflag
4671da177e4SLinus Torvalds 		&= ~(ECHO	/* disable echo input characters */
4681da177e4SLinus Torvalds 		| ECHONL	/* disable echo new line */
4691da177e4SLinus Torvalds 		| ICANON	/* disable erase, kill, werase, and rprnt special characters */
4701da177e4SLinus Torvalds 		| ISIG		/* disable interrupt, quit, and suspend special characters */
4711da177e4SLinus Torvalds 		| IEXTEN);	/* disable non-POSIX special characters */
4721da177e4SLinus Torvalds 
473998e8638SAlan Cox 	termios->c_cflag
4741da177e4SLinus Torvalds 		&= ~(CSIZE	/* no size */
4751da177e4SLinus Torvalds 		| PARENB	/* disable parity bit */
4761da177e4SLinus Torvalds 		| CBAUD);	/* clear current baud rate */
4771da177e4SLinus Torvalds 
478998e8638SAlan Cox 	termios->c_cflag
479998e8638SAlan Cox 		|= CS8;		/* character size 8 bits */
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	/*
4821da177e4SLinus Torvalds 	 * Force low_latency on; otherwise the pushes are scheduled;
4831da177e4SLinus Torvalds 	 * this is bad as it opens up the possibility of dropping bytes
4841da177e4SLinus Torvalds 	 * on the floor.  We don't want to drop bytes on the floor. :)
4851da177e4SLinus Torvalds 	 */
48695da310eSAlan Cox 	tty->low_latency = 1;
48795da310eSAlan Cox 	tty_encode_baud_rate(tty, 115200, 115200);
4881da177e4SLinus Torvalds }
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds static int __init empeg_init(void)
4921da177e4SLinus Torvalds {
4931da177e4SLinus Torvalds 	struct urb *urb;
4941da177e4SLinus Torvalds 	int i, retval;
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	/* create our write urb pool and transfer buffers */
4971da177e4SLinus Torvalds 	spin_lock_init(&write_urb_pool_lock);
4981da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
4991da177e4SLinus Torvalds 		urb = usb_alloc_urb(0, GFP_KERNEL);
5001da177e4SLinus Torvalds 		write_urb_pool[i] = urb;
5011da177e4SLinus Torvalds 		if (urb == NULL) {
5021da177e4SLinus Torvalds 			err("No more urbs???");
5031da177e4SLinus Torvalds 			continue;
5041da177e4SLinus Torvalds 		}
5051da177e4SLinus Torvalds 
50693c46795SAlan Cox 		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
50793c46795SAlan Cox 								GFP_KERNEL);
5081da177e4SLinus Torvalds 		if (!urb->transfer_buffer) {
5091da177e4SLinus Torvalds 			err("%s - out of memory for urb buffers.",
510441b62c1SHarvey Harrison 			    __func__);
5111da177e4SLinus Torvalds 			continue;
5121da177e4SLinus Torvalds 		}
5131da177e4SLinus Torvalds 	}
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	retval = usb_serial_register(&empeg_device);
5161da177e4SLinus Torvalds 	if (retval)
5171da177e4SLinus Torvalds 		goto failed_usb_serial_register;
5181da177e4SLinus Torvalds 	retval = usb_register(&empeg_driver);
5191da177e4SLinus Torvalds 	if (retval)
5201da177e4SLinus Torvalds 		goto failed_usb_register;
5211da177e4SLinus Torvalds 
522*c197a8dbSGreg Kroah-Hartman 	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
523*c197a8dbSGreg Kroah-Hartman 	       DRIVER_DESC "\n");
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	return 0;
5261da177e4SLinus Torvalds failed_usb_register:
5271da177e4SLinus Torvalds 	usb_serial_deregister(&empeg_device);
5281da177e4SLinus Torvalds failed_usb_serial_register:
5291da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5301da177e4SLinus Torvalds 		if (write_urb_pool[i]) {
5311da177e4SLinus Torvalds 			kfree(write_urb_pool[i]->transfer_buffer);
5321da177e4SLinus Torvalds 			usb_free_urb(write_urb_pool[i]);
5331da177e4SLinus Torvalds 		}
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds 	return retval;
5361da177e4SLinus Torvalds }
5371da177e4SLinus Torvalds 
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds static void __exit empeg_exit(void)
5401da177e4SLinus Torvalds {
5411da177e4SLinus Torvalds 	int i;
5421da177e4SLinus Torvalds 	unsigned long flags;
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 	usb_deregister(&empeg_driver);
5451da177e4SLinus Torvalds 	usb_serial_deregister(&empeg_device);
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 	spin_lock_irqsave(&write_urb_pool_lock, flags);
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5501da177e4SLinus Torvalds 		if (write_urb_pool[i]) {
55193c46795SAlan Cox 			/* FIXME - uncomment the following usb_kill_urb call
55293c46795SAlan Cox 			 * when the host controllers get fixed to set urb->dev
55393c46795SAlan Cox 			 * = NULL after the urb is finished.  Otherwise this
55493c46795SAlan Cox 			 * call oopses. */
5551da177e4SLinus Torvalds 			/* usb_kill_urb(write_urb_pool[i]); */
5561da177e4SLinus Torvalds 			kfree(write_urb_pool[i]->transfer_buffer);
5571da177e4SLinus Torvalds 			usb_free_urb(write_urb_pool[i]);
5581da177e4SLinus Torvalds 		}
5591da177e4SLinus Torvalds 	}
5601da177e4SLinus Torvalds 	spin_unlock_irqrestore(&write_urb_pool_lock, flags);
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds module_init(empeg_init);
5651da177e4SLinus Torvalds module_exit(empeg_exit);
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
5681da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
5691da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds module_param(debug, bool, S_IRUGO | S_IWUSR);
5721da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Debug enabled or not");
573