xref: /linux/drivers/usb/serial/empeg.c (revision ba9dc657af86d05d2971633e57d1f6f94ed60472)
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,
113*ba9dc657SGreg Kroah-Hartman 	.no_dynamic_id = 	1,
1141da177e4SLinus Torvalds };
1151da177e4SLinus Torvalds 
116ea65370dSGreg Kroah-Hartman static struct usb_serial_driver empeg_device = {
11718fcac35SGreg Kroah-Hartman 	.driver = {
1181da177e4SLinus Torvalds 		.owner =	THIS_MODULE,
119269bda1cSGreg Kroah-Hartman 		.name =		"empeg",
12018fcac35SGreg Kroah-Hartman 	},
1211da177e4SLinus Torvalds 	.id_table =		id_table,
1221da177e4SLinus Torvalds 	.num_interrupt_in =	0,
1231da177e4SLinus Torvalds 	.num_bulk_in =		1,
1241da177e4SLinus Torvalds 	.num_bulk_out =		1,
1251da177e4SLinus Torvalds 	.num_ports =		1,
1261da177e4SLinus Torvalds 	.open =			empeg_open,
1271da177e4SLinus Torvalds 	.close =		empeg_close,
1281da177e4SLinus Torvalds 	.throttle =		empeg_throttle,
1291da177e4SLinus Torvalds 	.unthrottle =		empeg_unthrottle,
1301da177e4SLinus Torvalds 	.attach =		empeg_startup,
1311da177e4SLinus Torvalds 	.shutdown =		empeg_shutdown,
1321da177e4SLinus Torvalds 	.ioctl =		empeg_ioctl,
1331da177e4SLinus Torvalds 	.set_termios =		empeg_set_termios,
1341da177e4SLinus Torvalds 	.write =		empeg_write,
1351da177e4SLinus Torvalds 	.write_room =		empeg_write_room,
1361da177e4SLinus Torvalds 	.chars_in_buffer =	empeg_chars_in_buffer,
1371da177e4SLinus Torvalds 	.write_bulk_callback =	empeg_write_bulk_callback,
1381da177e4SLinus Torvalds 	.read_bulk_callback =	empeg_read_bulk_callback,
1391da177e4SLinus Torvalds };
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds #define NUM_URBS			16
1421da177e4SLinus Torvalds #define URB_TRANSFER_BUFFER_SIZE	4096
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds static struct urb	*write_urb_pool[NUM_URBS];
1451da177e4SLinus Torvalds static spinlock_t	write_urb_pool_lock;
1461da177e4SLinus Torvalds static int		bytes_in;
1471da177e4SLinus Torvalds static int		bytes_out;
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /******************************************************************************
1501da177e4SLinus Torvalds  * Empeg specific driver functions
1511da177e4SLinus Torvalds  ******************************************************************************/
1521da177e4SLinus Torvalds static int empeg_open (struct usb_serial_port *port, struct file *filp)
1531da177e4SLinus Torvalds {
1541da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
1551da177e4SLinus Torvalds 	int result = 0;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	/* Force default termio settings */
1601da177e4SLinus Torvalds 	empeg_set_termios (port, NULL) ;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	bytes_in = 0;
1631da177e4SLinus Torvalds 	bytes_out = 0;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	/* Start reading from the device */
1661da177e4SLinus Torvalds 	usb_fill_bulk_urb(
1671da177e4SLinus Torvalds 		port->read_urb,
1681da177e4SLinus Torvalds 		serial->dev,
1691da177e4SLinus Torvalds 		usb_rcvbulkpipe(serial->dev,
1701da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
1711da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
1721da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
1731da177e4SLinus Torvalds 		empeg_read_bulk_callback,
1741da177e4SLinus Torvalds 		port);
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	if (result)
1791da177e4SLinus Torvalds 		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	return result;
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds 
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds static void empeg_close (struct usb_serial_port *port, struct file * filp)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, 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 
1961da177e4SLinus Torvalds static int empeg_write (struct usb_serial_port *port, const unsigned char *buf, int count)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	struct usb_serial *serial = port->serial;
1991da177e4SLinus Torvalds 	struct urb *urb;
2001da177e4SLinus Torvalds 	const unsigned char *current_position = buf;
2011da177e4SLinus Torvalds 	unsigned long flags;
2021da177e4SLinus Torvalds 	int status;
2031da177e4SLinus Torvalds 	int i;
2041da177e4SLinus Torvalds 	int bytes_sent = 0;
2051da177e4SLinus Torvalds 	int transfer_size;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	while (count > 0) {
2101da177e4SLinus Torvalds 
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) {
2261da177e4SLinus Torvalds 			dbg("%s - no more free urbs", __FUNCTION__);
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) {
2331da177e4SLinus Torvalds 				dev_err(&port->dev, "%s no more kernel memory...\n", __FUNCTION__);
2341da177e4SLinus Torvalds 				goto exit;
2351da177e4SLinus Torvalds 			}
2361da177e4SLinus Torvalds 		}
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 		transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds 		memcpy (urb->transfer_buffer, current_position, transfer_size);
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 		usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, urb->transfer_buffer);
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 		/* build up our urb */
2451da177e4SLinus Torvalds 		usb_fill_bulk_urb (
2461da177e4SLinus Torvalds 			urb,
2471da177e4SLinus Torvalds 			serial->dev,
2481da177e4SLinus Torvalds 			usb_sndbulkpipe(serial->dev,
2491da177e4SLinus Torvalds 				port->bulk_out_endpointAddress),
2501da177e4SLinus Torvalds 			urb->transfer_buffer,
2511da177e4SLinus Torvalds 			transfer_size,
2521da177e4SLinus Torvalds 			empeg_write_bulk_callback,
2531da177e4SLinus Torvalds 			port);
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 		/* send it down the pipe */
2561da177e4SLinus Torvalds 		status = usb_submit_urb(urb, GFP_ATOMIC);
2571da177e4SLinus Torvalds 		if (status) {
2581da177e4SLinus Torvalds 			dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __FUNCTION__, status);
2591da177e4SLinus Torvalds 			bytes_sent = status;
2601da177e4SLinus Torvalds 			break;
2611da177e4SLinus Torvalds 		}
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 		current_position += transfer_size;
2641da177e4SLinus Torvalds 		bytes_sent += transfer_size;
2651da177e4SLinus Torvalds 		count -= transfer_size;
2661da177e4SLinus Torvalds 		bytes_out += transfer_size;
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	}
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds exit:
2711da177e4SLinus Torvalds 	return bytes_sent;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static int empeg_write_room (struct usb_serial_port *port)
2771da177e4SLinus Torvalds {
2781da177e4SLinus Torvalds 	unsigned long flags;
2791da177e4SLinus Torvalds 	int i;
2801da177e4SLinus Torvalds 	int room = 0;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	/* tally up the number of bytes available */
2871da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
2881da177e4SLinus Torvalds 		if (write_urb_pool[i]->status != -EINPROGRESS) {
2891da177e4SLinus Torvalds 			room += URB_TRANSFER_BUFFER_SIZE;
2901da177e4SLinus Torvalds 		}
2911da177e4SLinus Torvalds 	}
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	dbg("%s - returns %d", __FUNCTION__, room);
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 	return (room);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds 
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds static int empeg_chars_in_buffer (struct usb_serial_port *port)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds 	unsigned long flags;
3051da177e4SLinus Torvalds 	int i;
3061da177e4SLinus Torvalds 	int chars = 0;
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	/* tally up the number of bytes waiting */
3131da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
3141da177e4SLinus Torvalds 		if (write_urb_pool[i]->status == -EINPROGRESS) {
3151da177e4SLinus Torvalds 			chars += URB_TRANSFER_BUFFER_SIZE;
3161da177e4SLinus Torvalds 		}
3171da177e4SLinus Torvalds 	}
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	dbg("%s - returns %d", __FUNCTION__, chars);
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	return (chars);
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
3291da177e4SLinus Torvalds {
3301da177e4SLinus Torvalds 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	if (urb->status) {
3351da177e4SLinus Torvalds 		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
3361da177e4SLinus Torvalds 		return;
3371da177e4SLinus Torvalds 	}
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	schedule_work(&port->work);
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
3441da177e4SLinus Torvalds {
3451da177e4SLinus Torvalds 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
3461da177e4SLinus Torvalds 	struct tty_struct *tty;
3471da177e4SLinus Torvalds 	unsigned char *data = urb->transfer_buffer;
3481da177e4SLinus Torvalds 	int i;
3491da177e4SLinus Torvalds 	int result;
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	if (urb->status) {
3541da177e4SLinus Torvalds 		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
3551da177e4SLinus Torvalds 		return;
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	tty = port->tty;
3611da177e4SLinus Torvalds 
3621da177e4SLinus Torvalds 	if (urb->actual_length) {
3631da177e4SLinus Torvalds 		for (i = 0; i < urb->actual_length ; ++i) {
3641da177e4SLinus Torvalds 			/* gb - 2000/11/13
3651da177e4SLinus Torvalds 			 * If we insert too many characters we'll overflow the buffer.
3661da177e4SLinus Torvalds 			 * This means we'll lose bytes - Decidedly bad.
3671da177e4SLinus Torvalds 			 */
3681da177e4SLinus Torvalds 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
3691da177e4SLinus Torvalds 				tty_flip_buffer_push(tty);
3701da177e4SLinus Torvalds 				}
3711da177e4SLinus Torvalds 			tty_insert_flip_char(tty, data[i], 0);
3721da177e4SLinus Torvalds 		}
3731da177e4SLinus Torvalds 		/* gb - 2000/11/13
3741da177e4SLinus Torvalds 		 * Goes straight through instead of scheduling - if tty->low_latency is set.
3751da177e4SLinus Torvalds 		 */
3761da177e4SLinus Torvalds 		tty_flip_buffer_push(tty);
3771da177e4SLinus Torvalds 		bytes_in += urb->actual_length;
3781da177e4SLinus Torvalds 	}
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	/* Continue trying to always read  */
3811da177e4SLinus Torvalds 	usb_fill_bulk_urb(
3821da177e4SLinus Torvalds 		port->read_urb,
3831da177e4SLinus Torvalds 		port->serial->dev,
3841da177e4SLinus Torvalds 		usb_rcvbulkpipe(port->serial->dev,
3851da177e4SLinus Torvalds 			port->bulk_in_endpointAddress),
3861da177e4SLinus Torvalds 		port->read_urb->transfer_buffer,
3871da177e4SLinus Torvalds 		port->read_urb->transfer_buffer_length,
3881da177e4SLinus Torvalds 		empeg_read_bulk_callback,
3891da177e4SLinus Torvalds 		port);
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	if (result)
3941da177e4SLinus Torvalds 		dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	return;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds static void empeg_throttle (struct usb_serial_port *port)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4041da177e4SLinus Torvalds 	usb_kill_urb(port->read_urb);
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds static void empeg_unthrottle (struct usb_serial_port *port)
4091da177e4SLinus Torvalds {
4101da177e4SLinus Torvalds 	int result;
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	port->read_urb->dev = port->serial->dev;
4151da177e4SLinus Torvalds 
4161da177e4SLinus Torvalds 	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	if (result)
4191da177e4SLinus Torvalds 		dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	return;
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds static int  empeg_startup (struct usb_serial *serial)
4261da177e4SLinus Torvalds {
4271da177e4SLinus Torvalds 	int r;
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds 	dbg("%s", __FUNCTION__);
4301da177e4SLinus Torvalds 
4311da177e4SLinus Torvalds 	if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
4321da177e4SLinus Torvalds 		err("active config #%d != 1 ??",
4331da177e4SLinus Torvalds 			serial->dev->actconfig->desc.bConfigurationValue);
4341da177e4SLinus Torvalds 		return -ENODEV;
4351da177e4SLinus Torvalds 	}
4361da177e4SLinus Torvalds 	dbg("%s - reset config", __FUNCTION__);
4371da177e4SLinus Torvalds 	r = usb_reset_configuration (serial->dev);
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 	/* continue on with initialization */
4401da177e4SLinus Torvalds 	return r;
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds }
4431da177e4SLinus Torvalds 
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds static void empeg_shutdown (struct usb_serial *serial)
4461da177e4SLinus Torvalds {
4471da177e4SLinus Torvalds 	dbg ("%s", __FUNCTION__);
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds 
4511da177e4SLinus Torvalds static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
4521da177e4SLinus Torvalds {
4531da177e4SLinus Torvalds 	dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 	return -ENOIOCTLCMD;
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds 
4581da177e4SLinus Torvalds 
4591da177e4SLinus Torvalds static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
4601da177e4SLinus Torvalds {
4611da177e4SLinus Torvalds 
4621da177e4SLinus Torvalds 	dbg("%s - port %d", __FUNCTION__, port->number);
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 	if ((!port->tty) || (!port->tty->termios)) {
4651da177e4SLinus Torvalds 		dbg("%s - no tty structures", __FUNCTION__);
4661da177e4SLinus Torvalds 		return;
4671da177e4SLinus Torvalds 	}
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds 	/*
4701da177e4SLinus Torvalds          * The empeg-car player wants these particular tty settings.
4711da177e4SLinus Torvalds          * You could, for example, change the baud rate, however the
4721da177e4SLinus Torvalds          * player only supports 115200 (currently), so there is really
4731da177e4SLinus Torvalds          * no point in support for changes to the tty settings.
4741da177e4SLinus Torvalds          * (at least for now)
4751da177e4SLinus Torvalds          *
4761da177e4SLinus Torvalds          * The default requirements for this device are:
4771da177e4SLinus Torvalds          */
4781da177e4SLinus Torvalds 	port->tty->termios->c_iflag
4791da177e4SLinus Torvalds 		&= ~(IGNBRK	/* disable ignore break */
4801da177e4SLinus Torvalds 		| BRKINT	/* disable break causes interrupt */
4811da177e4SLinus Torvalds 		| PARMRK	/* disable mark parity errors */
4821da177e4SLinus Torvalds 		| ISTRIP	/* disable clear high bit of input characters */
4831da177e4SLinus Torvalds 		| INLCR		/* disable translate NL to CR */
4841da177e4SLinus Torvalds 		| IGNCR		/* disable ignore CR */
4851da177e4SLinus Torvalds 		| ICRNL		/* disable translate CR to NL */
4861da177e4SLinus Torvalds 		| IXON);	/* disable enable XON/XOFF flow control */
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds 	port->tty->termios->c_oflag
4891da177e4SLinus Torvalds 		&= ~OPOST;	/* disable postprocess output characters */
4901da177e4SLinus Torvalds 
4911da177e4SLinus Torvalds 	port->tty->termios->c_lflag
4921da177e4SLinus Torvalds 		&= ~(ECHO	/* disable echo input characters */
4931da177e4SLinus Torvalds 		| ECHONL	/* disable echo new line */
4941da177e4SLinus Torvalds 		| ICANON	/* disable erase, kill, werase, and rprnt special characters */
4951da177e4SLinus Torvalds 		| ISIG		/* disable interrupt, quit, and suspend special characters */
4961da177e4SLinus Torvalds 		| IEXTEN);	/* disable non-POSIX special characters */
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	port->tty->termios->c_cflag
4991da177e4SLinus Torvalds 		&= ~(CSIZE	/* no size */
5001da177e4SLinus Torvalds 		| PARENB	/* disable parity bit */
5011da177e4SLinus Torvalds 		| CBAUD);	/* clear current baud rate */
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	port->tty->termios->c_cflag
5041da177e4SLinus Torvalds 		|= (CS8		/* character size 8 bits */
5051da177e4SLinus Torvalds 		| B115200);	/* baud rate 115200 */
5061da177e4SLinus Torvalds 
5071da177e4SLinus Torvalds 	/*
5081da177e4SLinus Torvalds 	 * Force low_latency on; otherwise the pushes are scheduled;
5091da177e4SLinus Torvalds 	 * this is bad as it opens up the possibility of dropping bytes
5101da177e4SLinus Torvalds 	 * on the floor.  We don't want to drop bytes on the floor. :)
5111da177e4SLinus Torvalds 	 */
5121da177e4SLinus Torvalds 	port->tty->low_latency = 1;
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 	return;
5151da177e4SLinus Torvalds }
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds static int __init empeg_init (void)
5191da177e4SLinus Torvalds {
5201da177e4SLinus Torvalds 	struct urb *urb;
5211da177e4SLinus Torvalds 	int i, retval;
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	/* create our write urb pool and transfer buffers */
5241da177e4SLinus Torvalds 	spin_lock_init (&write_urb_pool_lock);
5251da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5261da177e4SLinus Torvalds 		urb = usb_alloc_urb(0, GFP_KERNEL);
5271da177e4SLinus Torvalds 		write_urb_pool[i] = urb;
5281da177e4SLinus Torvalds 		if (urb == NULL) {
5291da177e4SLinus Torvalds 			err("No more urbs???");
5301da177e4SLinus Torvalds 			continue;
5311da177e4SLinus Torvalds 		}
5321da177e4SLinus Torvalds 
5331da177e4SLinus Torvalds 		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
5341da177e4SLinus Torvalds 		if (!urb->transfer_buffer) {
5351da177e4SLinus Torvalds 			err("%s - out of memory for urb buffers.",
5361da177e4SLinus Torvalds 			    __FUNCTION__);
5371da177e4SLinus Torvalds 			continue;
5381da177e4SLinus Torvalds 		}
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	retval = usb_serial_register(&empeg_device);
5421da177e4SLinus Torvalds 	if (retval)
5431da177e4SLinus Torvalds 		goto failed_usb_serial_register;
5441da177e4SLinus Torvalds 	retval = usb_register(&empeg_driver);
5451da177e4SLinus Torvalds 	if (retval)
5461da177e4SLinus Torvalds 		goto failed_usb_register;
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	info(DRIVER_VERSION ":" DRIVER_DESC);
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	return 0;
5511da177e4SLinus Torvalds failed_usb_register:
5521da177e4SLinus Torvalds 	usb_serial_deregister(&empeg_device);
5531da177e4SLinus Torvalds failed_usb_serial_register:
5541da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5551da177e4SLinus Torvalds 		if (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 	return retval;
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds static void __exit empeg_exit (void)
5651da177e4SLinus Torvalds {
5661da177e4SLinus Torvalds 	int i;
5671da177e4SLinus Torvalds 	unsigned long flags;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	usb_deregister(&empeg_driver);
5701da177e4SLinus Torvalds 	usb_serial_deregister (&empeg_device);
5711da177e4SLinus Torvalds 
5721da177e4SLinus Torvalds 	spin_lock_irqsave (&write_urb_pool_lock, flags);
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 	for (i = 0; i < NUM_URBS; ++i) {
5751da177e4SLinus Torvalds 		if (write_urb_pool[i]) {
5761da177e4SLinus Torvalds 			/* FIXME - uncomment the following usb_kill_urb call when
5771da177e4SLinus Torvalds 			 * the host controllers get fixed to set urb->dev = NULL after
5781da177e4SLinus Torvalds 			 * the urb is finished.  Otherwise this call oopses. */
5791da177e4SLinus Torvalds 			/* usb_kill_urb(write_urb_pool[i]); */
5801da177e4SLinus Torvalds 			kfree(write_urb_pool[i]->transfer_buffer);
5811da177e4SLinus Torvalds 			usb_free_urb (write_urb_pool[i]);
5821da177e4SLinus Torvalds 		}
5831da177e4SLinus Torvalds 	}
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds module_init(empeg_init);
5901da177e4SLinus Torvalds module_exit(empeg_exit);
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds MODULE_AUTHOR( DRIVER_AUTHOR );
5931da177e4SLinus Torvalds MODULE_DESCRIPTION( DRIVER_DESC );
5941da177e4SLinus Torvalds MODULE_LICENSE("GPL");
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds module_param(debug, bool, S_IRUGO | S_IWUSR);
5971da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "Debug enabled or not");
598