Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 1048 → Rev 1049

/shark/trunk/drivers/usb/serial/pl2303.c
1,818 → 1,816
/*
* Prolific PL2303 USB to serial adaptor driver
*
* Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2003 IBM Corp.
*
* Original driver for 2.2.x by anonymous
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* 2002_Mar_26 gkh
* allowed driver to work properly if there is no tty assigned to a port
* (this happens for serial console devices.)
*
* 2001_Oct_06 gkh
* Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it.
*
* 2001_Sep_19 gkh
* Added break support.
*
* 2001_Aug_30 gkh
* fixed oops in write_bulk_callback.
*
* 2001_Aug_28 gkh
* reworked buffer logic to be like other usb-serial drivers. Hopefully
* removing some reported problems.
*
* 2001_Jun_06 gkh
* finished porting to 2.4 format.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
#include "pl2303.h"
 
/*
* Version Information
*/
#define DRIVER_VERSION "v0.10"
#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
 
static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
{ } /* Terminating entry */
};
 
MODULE_DEVICE_TABLE (usb, id_table);
 
static struct usb_driver pl2303_driver = {
.owner = THIS_MODULE,
.name = "pl2303",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
};
 
#define SET_LINE_REQUEST_TYPE 0x21
#define SET_LINE_REQUEST 0x20
 
#define SET_CONTROL_REQUEST_TYPE 0x21
#define SET_CONTROL_REQUEST 0x22
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
 
#define BREAK_REQUEST_TYPE 0x21
#define BREAK_REQUEST 0x23
#define BREAK_ON 0xffff
#define BREAK_OFF 0x0000
 
#define GET_LINE_REQUEST_TYPE 0xa1
#define GET_LINE_REQUEST 0x21
 
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
 
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
 
#define UART_STATE 0x08
#define UART_DCD 0x01
#define UART_DSR 0x02
#define UART_BREAK_ERROR 0x04
#define UART_RING 0x08
#define UART_FRAME_ERROR 0x10
#define UART_PARITY_ERROR 0x20
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
 
/* function prototypes for a PL2303 serial converter */
static int pl2303_open (struct usb_serial_port *port, struct file *filp);
static void pl2303_close (struct usb_serial_port *port, struct file *filp);
static void pl2303_set_termios (struct usb_serial_port *port,
struct termios *old);
static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static int pl2303_write (struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count);
static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static int pl2303_startup (struct usb_serial *serial);
static void pl2303_shutdown (struct usb_serial *serial);
 
 
/* All of the device info needed for the PL2303 SIO serial converter */
static struct usb_serial_device_type pl2303_device = {
.owner = THIS_MODULE,
.name = "PL-2303",
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = pl2303_open,
.close = pl2303_close,
.write = pl2303_write,
.ioctl = pl2303_ioctl,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
.tiocmset = pl2303_tiocmset,
.read_bulk_callback = pl2303_read_bulk_callback,
.read_int_callback = pl2303_read_int_callback,
.write_bulk_callback = pl2303_write_bulk_callback,
.attach = pl2303_startup,
.shutdown = pl2303_shutdown,
};
 
struct pl2303_private {
spinlock_t lock;
u8 line_control;
u8 line_status;
u8 termios_initialized;
};
 
 
static int pl2303_startup (struct usb_serial *serial)
{
struct pl2303_private *priv;
int i;
 
for (i = 0; i < serial->num_ports; ++i) {
priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
memset (priv, 0x00, sizeof (struct pl2303_private));
spin_lock_init(&priv->lock);
usb_set_serial_port_data(serial->port[i], priv);
}
return 0;
}
 
static int set_control_lines (struct usb_device *dev, u8 value)
{
int retval;
retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
return retval;
}
 
static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
int result;
 
dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
 
if (port->write_urb->status == -EINPROGRESS) {
dbg("%s - already writing", __FUNCTION__);
return 0;
}
 
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (from_user) {
if (copy_from_user (port->write_urb->transfer_buffer, buf, count))
return -EFAULT;
} else {
memcpy (port->write_urb->transfer_buffer, buf, count);
}
usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
else
result = count;
 
return result;
}
 
 
 
static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int cflag;
unsigned char *buf;
int baud;
int i;
u8 control;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if ((!port->tty) || (!port->tty->termios)) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
 
spin_lock_irqsave(&priv->lock, flags);
 
if (!priv->termios_initialized) {
printk(KERN_INFO "@####### termios initializated\n");
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
 
spin_unlock_irqrestore(&priv->lock, flags);
 
cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
return;
}
}
 
buf = kmalloc (7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return;
}
memset (buf, 0x00, 0x07);
i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
case CS5: buf[6] = 5; break;
case CS6: buf[6] = 6; break;
case CS7: buf[6] = 7; break;
default:
case CS8: buf[6] = 8; break;
}
dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
}
 
baud = 0;
switch (cflag & CBAUD) {
case B0: baud = 0; break;
case B75: baud = 75; break;
case B150: baud = 150; break;
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B1800: baud = 1800; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B19200: baud = 19200; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
default:
dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
break;
}
dbg("%s - baud = %d", __FUNCTION__, baud);
if (baud) {
buf[0] = baud & 0xff;
buf[1] = (baud >> 8) & 0xff;
buf[2] = (baud >> 16) & 0xff;
buf[3] = (baud >> 24) & 0xff;
}
 
/* For reference buf[4]=0 is 1 stop bits */
/* For reference buf[4]=1 is 1.5 stop bits */
/* For reference buf[4]=2 is 2 stop bits */
if (cflag & CSTOPB) {
buf[4] = 2;
dbg("%s - stop bits = 2", __FUNCTION__);
} else {
buf[4] = 0;
dbg("%s - stop bits = 1", __FUNCTION__);
}
 
if (cflag & PARENB) {
/* For reference buf[5]=0 is none parity */
/* For reference buf[5]=1 is odd parity */
/* For reference buf[5]=2 is even parity */
/* For reference buf[5]=3 is mark parity */
/* For reference buf[5]=4 is space parity */
if (cflag & PARODD) {
buf[5] = 1;
dbg("%s - parity = odd", __FUNCTION__);
} else {
buf[5] = 2;
dbg("%s - parity = even", __FUNCTION__);
}
} else {
buf[5] = 0;
dbg("%s - parity = none", __FUNCTION__);
}
 
i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0x21:0x20:0:0 %d", i);
 
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines(serial->dev, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
 
i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
if (cflag & CRTSCTS) {
i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
0x0, 0x41, NULL, 0, 100);
dbg ("0x40:0x1:0x0:0x41 %d", i);
}
 
kfree (buf);
}
 
 
static int pl2303_open (struct usb_serial_port *port, struct file *filp)
{
struct termios tmp_termios;
struct usb_serial *serial = port->serial;
unsigned char buf[10];
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return -ENODEV;
dbg("%s - port %d", __FUNCTION__, port->number);
 
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
 
#define FISH(a,b,c,d) \
result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
b, a, c, d, buf, 1, 100); \
dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
 
#define SOUP(a,b,c,d) \
result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
b, a, c, d, NULL, 0, 100); \
dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
 
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
 
/* Setup termios */
if (port->tty) {
printk(KERN_INFO "#####@ set termios");
pl2303_set_termios (port, &tmp_termios);
}
 
//FIXME: need to assert RTS and DTR if CRTSCTS off
 
dbg("%s - submitting read urb", __FUNCTION__);
port->read_urb->dev = serial->dev;
result = usb_submit_urb (port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
pl2303_close (port, NULL);
return -EPROTO;
}
 
dbg("%s - submitting interrupt urb", __FUNCTION__);
port->interrupt_in_urb->dev = serial->dev;
result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
pl2303_close (port, NULL);
return -EPROTO;
}
return 0;
}
 
 
static void pl2303_close (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial;
struct pl2303_private *priv;
unsigned long flags;
unsigned int c_cflag;
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
dbg("%s - port %d", __FUNCTION__, port->number);
 
/* shutdown our urbs */
dbg("%s - shutting down urbs", __FUNCTION__);
result = usb_unlink_urb (port->write_urb);
if (result)
dbg("%s - usb_unlink_urb (write_urb)"
" failed with reason: %d", __FUNCTION__,
result);
 
result = usb_unlink_urb (port->read_urb);
if (result)
dbg("%s - usb_unlink_urb (read_urb) "
"failed with reason: %d", __FUNCTION__,
result);
 
result = usb_unlink_urb (port->interrupt_in_urb);
if (result)
dbg("%s - usb_unlink_urb (interrupt_in_urb)"
" failed with reason: %d", __FUNCTION__,
result);
 
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore (&priv->lock, flags);
set_control_lines (port->serial->dev, 0);
}
}
 
}
 
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
 
spin_lock_irqsave (&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR)
priv->line_control |= CONTROL_DTR;
if (clear & TIOCM_RTS)
priv->line_control &= ~CONTROL_RTS;
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
control = priv->line_control;
spin_unlock_irqrestore (&priv->lock, flags);
 
return set_control_lines (port->serial->dev, control);
}
 
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr;
unsigned int status;
unsigned int result;
 
dbg("%s (%d)", __FUNCTION__, port->number);
 
spin_lock_irqsave (&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
spin_unlock_irqrestore (&priv->lock, flags);
 
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
| ((status & UART_CTS) ? TIOCM_CTS : 0)
| ((status & UART_DSR) ? TIOCM_DSR : 0)
| ((status & UART_RING) ? TIOCM_RI : 0)
| ((status & UART_DCD) ? TIOCM_CD : 0);
 
dbg("%s - result = %x", __FUNCTION__, result);
 
return result;
}
 
static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
{
dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
 
switch (cmd) {
default:
dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
break;
}
 
return -ENOIOCTLCMD;
}
 
static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
{
struct usb_serial *serial = port->serial;
u16 state;
int result;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__);
 
result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result)
dbg("%s - error sending break = %d", __FUNCTION__, result);
}
 
 
static void pl2303_shutdown (struct usb_serial *serial)
{
int i;
 
dbg("%s", __FUNCTION__);
 
for (i = 0; i < serial->num_ports; ++i) {
kfree (usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
}
 
 
static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int status;
 
dbg("%s (%d)", __FUNCTION__, port->number);
 
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
 
if (!serial) {
return;
}
 
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
if (urb->actual_length < UART_STATE)
goto exit;
 
/* Save off the uart status for others to look at */
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = data[UART_STATE];
spin_unlock_irqrestore(&priv->lock, flags);
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, status);
}
 
 
static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct pl2303_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int i;
int result;
u8 status;
char tty_flag;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
 
 
if (urb->status) {
dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
if (!port->open_count) {
dbg("%s - port is closed, exiting.", __FUNCTION__);
return;
}
if (urb->status == -EPROTO) {
/* PL2303 mysteriously fails with -EPROTO reschedule the read */
dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
urb->status = 0;
urb->dev = serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
return;
}
dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
return;
}
 
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
/* get tty_flag from status */
tty_flag = TTY_NORMAL;
 
spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
spin_unlock_irqrestore(&priv->lock, flags);
 
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
if (status & UART_BREAK_ERROR )
tty_flag = TTY_BREAK;
else if (status & UART_PARITY_ERROR)
tty_flag = TTY_PARITY;
else if (status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
 
tty = port->tty;
if (tty && urb->actual_length) {
/* overrun is special, not associated with a char */
if (status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
for (i = 0; i < urb->actual_length; ++i) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
//**#ifdef DEBUG_ME
tty_insert_flip_char (tty, data[i], tty_flag);
//**#endif /* DEBUG_ME */
}
tty_flip_buffer_push (tty);
}
 
 
/* Schedule the next read _if_ we are still open */
if (port->open_count) {
urb->dev = serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
 
 
return;
}
 
 
 
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
/* error in the urb, so we have to resubmit it */
if (serial_paranoia_check (port->serial, __FUNCTION__)) {
return;
}
dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
 
return;
}
 
schedule_work(&port->work);
}
 
 
/*static*/ int __init pl2303_init (void)
{
int retval;
retval = usb_serial_register(&pl2303_device);
if (retval)
goto failed_usb_serial_register;
retval = usb_register(&pl2303_driver);
if (retval)
goto failed_usb_register;
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
failed_usb_register:
usb_serial_deregister(&pl2303_device);
failed_usb_serial_register:
return retval;
}
 
 
/*static*/ void __exit pl2303_exit (void)
{
usb_deregister (&pl2303_driver);
usb_serial_deregister (&pl2303_device);
}
 
 
module_init(pl2303_init);
module_exit(pl2303_exit);
 
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
 
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
 
/*
* Prolific PL2303 USB to serial adaptor driver
*
* Copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2003 IBM Corp.
*
* Original driver for 2.2.x by anonymous
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* 2002_Mar_26 gkh
* allowed driver to work properly if there is no tty assigned to a port
* (this happens for serial console devices.)
*
* 2001_Oct_06 gkh
* Added RTS and DTR line control. Thanks to joe@bndlg.de for parts of it.
*
* 2001_Sep_19 gkh
* Added break support.
*
* 2001_Aug_30 gkh
* fixed oops in write_bulk_callback.
*
* 2001_Aug_28 gkh
* reworked buffer logic to be like other usb-serial drivers. Hopefully
* removing some reported problems.
*
* 2001_Jun_06 gkh
* finished porting to 2.4 format.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
#include "pl2303.h"
 
/*
* Version Information
*/
#define DRIVER_VERSION "v0.10"
#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 
 
static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
{ } /* Terminating entry */
};
 
MODULE_DEVICE_TABLE (usb, id_table);
 
static struct usb_driver pl2303_driver = {
.owner = THIS_MODULE,
.name = "pl2303",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
};
 
#define SET_LINE_REQUEST_TYPE 0x21
#define SET_LINE_REQUEST 0x20
 
#define SET_CONTROL_REQUEST_TYPE 0x21
#define SET_CONTROL_REQUEST 0x22
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
 
#define BREAK_REQUEST_TYPE 0x21
#define BREAK_REQUEST 0x23
#define BREAK_ON 0xffff
#define BREAK_OFF 0x0000
 
#define GET_LINE_REQUEST_TYPE 0xa1
#define GET_LINE_REQUEST 0x21
 
#define VENDOR_WRITE_REQUEST_TYPE 0x40
#define VENDOR_WRITE_REQUEST 0x01
 
#define VENDOR_READ_REQUEST_TYPE 0xc0
#define VENDOR_READ_REQUEST 0x01
 
#define UART_STATE 0x08
#define UART_DCD 0x01
#define UART_DSR 0x02
#define UART_BREAK_ERROR 0x04
#define UART_RING 0x08
#define UART_FRAME_ERROR 0x10
#define UART_PARITY_ERROR 0x20
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
 
/* function prototypes for a PL2303 serial converter */
static int pl2303_open (struct usb_serial_port *port, struct file *filp);
static void pl2303_close (struct usb_serial_port *port, struct file *filp);
static void pl2303_set_termios (struct usb_serial_port *port,
struct termios *old);
static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg);
static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static int pl2303_write (struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count);
static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static int pl2303_startup (struct usb_serial *serial);
static void pl2303_shutdown (struct usb_serial *serial);
 
 
/* All of the device info needed for the PL2303 SIO serial converter */
static struct usb_serial_device_type pl2303_device = {
.owner = THIS_MODULE,
.name = "PL-2303",
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = pl2303_open,
.close = pl2303_close,
.write = pl2303_write,
.ioctl = pl2303_ioctl,
.break_ctl = pl2303_break_ctl,
.set_termios = pl2303_set_termios,
.tiocmget = pl2303_tiocmget,
.tiocmset = pl2303_tiocmset,
.read_bulk_callback = pl2303_read_bulk_callback,
.read_int_callback = pl2303_read_int_callback,
.write_bulk_callback = pl2303_write_bulk_callback,
.attach = pl2303_startup,
.shutdown = pl2303_shutdown,
};
 
struct pl2303_private {
spinlock_t lock;
u8 line_control;
u8 line_status;
u8 termios_initialized;
};
 
 
static int pl2303_startup (struct usb_serial *serial)
{
struct pl2303_private *priv;
int i;
 
for (i = 0; i < serial->num_ports; ++i) {
priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
memset (priv, 0x00, sizeof (struct pl2303_private));
spin_lock_init(&priv->lock);
usb_set_serial_port_data(serial->port[i], priv);
}
return 0;
}
 
static int set_control_lines (struct usb_device *dev, u8 value)
{
int retval;
retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
return retval;
}
 
static int pl2303_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
{
int result;
 
dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
 
if (port->write_urb->status == -EINPROGRESS) {
dbg("%s - already writing", __FUNCTION__);
return 0;
}
 
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
if (from_user) {
if (copy_from_user (port->write_urb->transfer_buffer, buf, count))
return -EFAULT;
} else {
memcpy (port->write_urb->transfer_buffer, buf, count);
}
usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
 
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
else
result = count;
 
return result;
}
 
 
 
static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int cflag;
unsigned char *buf;
int baud;
int i;
u8 control;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if ((!port->tty) || (!port->tty->termios)) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
 
spin_lock_irqsave(&priv->lock, flags);
 
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
 
spin_unlock_irqrestore(&priv->lock, flags);
 
cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
return;
}
}
 
buf = kmalloc (7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return;
}
memset (buf, 0x00, 0x07);
i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
 
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
case CS5: buf[6] = 5; break;
case CS6: buf[6] = 6; break;
case CS7: buf[6] = 7; break;
default:
case CS8: buf[6] = 8; break;
}
dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
}
 
baud = 0;
switch (cflag & CBAUD) {
case B0: baud = 0; break;
case B75: baud = 75; break;
case B150: baud = 150; break;
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B1800: baud = 1800; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B19200: baud = 19200; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
default:
dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
break;
}
dbg("%s - baud = %d", __FUNCTION__, baud);
if (baud) {
buf[0] = baud & 0xff;
buf[1] = (baud >> 8) & 0xff;
buf[2] = (baud >> 16) & 0xff;
buf[3] = (baud >> 24) & 0xff;
}
 
/* For reference buf[4]=0 is 1 stop bits */
/* For reference buf[4]=1 is 1.5 stop bits */
/* For reference buf[4]=2 is 2 stop bits */
if (cflag & CSTOPB) {
buf[4] = 2;
dbg("%s - stop bits = 2", __FUNCTION__);
} else {
buf[4] = 0;
dbg("%s - stop bits = 1", __FUNCTION__);
}
 
if (cflag & PARENB) {
/* For reference buf[5]=0 is none parity */
/* For reference buf[5]=1 is odd parity */
/* For reference buf[5]=2 is even parity */
/* For reference buf[5]=3 is mark parity */
/* For reference buf[5]=4 is space parity */
if (cflag & PARODD) {
buf[5] = 1;
dbg("%s - parity = odd", __FUNCTION__);
} else {
buf[5] = 2;
dbg("%s - parity = even", __FUNCTION__);
}
} else {
buf[5] = 0;
dbg("%s - parity = none", __FUNCTION__);
}
 
i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0x21:0x20:0:0 %d", i);
 
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
else
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines(serial->dev, control);
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
 
i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
 
if (cflag & CRTSCTS) {
i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
0x0, 0x41, NULL, 0, 100);
dbg ("0x40:0x1:0x0:0x41 %d", i);
}
 
kfree (buf);
}
 
 
static int pl2303_open (struct usb_serial_port *port, struct file *filp)
{
struct termios tmp_termios;
struct usb_serial *serial = port->serial;
unsigned char buf[10];
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return -ENODEV;
dbg("%s - port %d", __FUNCTION__, port->number);
 
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
 
#define FISH(a,b,c,d) \
result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
b, a, c, d, buf, 1, 100); \
dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
 
#define SOUP(a,b,c,d) \
result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
b, a, c, d, NULL, 0, 100); \
dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
 
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
 
/* Setup termios */
if (port->tty) {
pl2303_set_termios (port, &tmp_termios);
}
 
//FIXME: need to assert RTS and DTR if CRTSCTS off
 
dbg("%s - submitting read urb", __FUNCTION__);
port->read_urb->dev = serial->dev;
result = usb_submit_urb (port->read_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
pl2303_close (port, NULL);
return -EPROTO;
}
 
dbg("%s - submitting interrupt urb", __FUNCTION__);
port->interrupt_in_urb->dev = serial->dev;
result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
pl2303_close (port, NULL);
return -EPROTO;
}
return 0;
}
 
 
static void pl2303_close (struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial;
struct pl2303_private *priv;
unsigned long flags;
unsigned int c_cflag;
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
dbg("%s - port %d", __FUNCTION__, port->number);
 
/* shutdown our urbs */
dbg("%s - shutting down urbs", __FUNCTION__);
result = usb_unlink_urb (port->write_urb);
if (result)
dbg("%s - usb_unlink_urb (write_urb)"
" failed with reason: %d", __FUNCTION__,
result);
 
result = usb_unlink_urb (port->read_urb);
if (result)
dbg("%s - usb_unlink_urb (read_urb) "
"failed with reason: %d", __FUNCTION__,
result);
 
result = usb_unlink_urb (port->interrupt_in_urb);
if (result)
dbg("%s - usb_unlink_urb (interrupt_in_urb)"
" failed with reason: %d", __FUNCTION__,
result);
 
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore (&priv->lock, flags);
set_control_lines (port->serial->dev, 0);
}
}
 
}
 
static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
 
spin_lock_irqsave (&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR)
priv->line_control |= CONTROL_DTR;
if (clear & TIOCM_RTS)
priv->line_control &= ~CONTROL_RTS;
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
control = priv->line_control;
spin_unlock_irqrestore (&priv->lock, flags);
 
return set_control_lines (port->serial->dev, control);
}
 
static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int mcr;
unsigned int status;
unsigned int result;
 
dbg("%s (%d)", __FUNCTION__, port->number);
 
spin_lock_irqsave (&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
spin_unlock_irqrestore (&priv->lock, flags);
 
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
| ((status & UART_CTS) ? TIOCM_CTS : 0)
| ((status & UART_DSR) ? TIOCM_DSR : 0)
| ((status & UART_RING) ? TIOCM_RI : 0)
| ((status & UART_DCD) ? TIOCM_CD : 0);
 
dbg("%s - result = %x", __FUNCTION__, result);
 
return result;
}
 
static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
{
dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
 
switch (cmd) {
default:
dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
break;
}
 
return -ENOIOCTLCMD;
}
 
static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
{
struct usb_serial *serial = port->serial;
u16 state;
int result;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__);
 
result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result)
dbg("%s - error sending break = %d", __FUNCTION__, result);
}
 
 
static void pl2303_shutdown (struct usb_serial *serial)
{
int i;
 
dbg("%s", __FUNCTION__);
 
for (i = 0; i < serial->num_ports; ++i) {
kfree (usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
}
 
 
static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int status;
 
dbg("%s (%d)", __FUNCTION__, port->number);
 
switch (urb->status) {
case 0:
/* success */
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
 
if (!serial) {
return;
}
 
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
if (urb->actual_length < UART_STATE)
goto exit;
 
/* Save off the uart status for others to look at */
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = data[UART_STATE];
spin_unlock_irqrestore(&priv->lock, flags);
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, status);
}
 
 
static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
struct pl2303_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int i;
int result;
u8 status;
char tty_flag;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
 
 
if (urb->status) {
dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
if (!port->open_count) {
dbg("%s - port is closed, exiting.", __FUNCTION__);
return;
}
if (urb->status == -EPROTO) {
/* PL2303 mysteriously fails with -EPROTO reschedule the read */
dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
urb->status = 0;
urb->dev = serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
return;
}
dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
return;
}
 
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
/* get tty_flag from status */
tty_flag = TTY_NORMAL;
 
spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
spin_unlock_irqrestore(&priv->lock, flags);
 
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
if (status & UART_BREAK_ERROR )
tty_flag = TTY_BREAK;
else if (status & UART_PARITY_ERROR)
tty_flag = TTY_PARITY;
else if (status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
 
tty = port->tty;
if (tty && urb->actual_length) {
/* overrun is special, not associated with a char */
if (status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
for (i = 0; i < urb->actual_length; ++i) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
tty_flip_buffer_push(tty);
}
//**#ifdef DEBUG_ME
tty_insert_flip_char (tty, data[i], tty_flag);
//**#endif /* DEBUG_ME */
}
tty_flip_buffer_push (tty);
}
 
 
/* Schedule the next read _if_ we are still open */
if (port->open_count) {
urb->dev = serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
 
 
return;
}
 
 
 
static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
int result;
 
if (port_paranoia_check (port, __FUNCTION__))
return;
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
/* error in the urb, so we have to resubmit it */
if (serial_paranoia_check (port->serial, __FUNCTION__)) {
return;
}
dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
 
return;
}
 
schedule_work(&port->work);
}
 
 
/*static*/ int __init pl2303_init (void)
{
int retval;
retval = usb_serial_register(&pl2303_device);
if (retval)
goto failed_usb_serial_register;
retval = usb_register(&pl2303_driver);
if (retval)
goto failed_usb_register;
info(DRIVER_DESC " " DRIVER_VERSION);
return 0;
failed_usb_register:
usb_serial_deregister(&pl2303_device);
failed_usb_serial_register:
return retval;
}
 
 
/*static*/ void __exit pl2303_exit (void)
{
usb_deregister (&pl2303_driver);
usb_serial_deregister (&pl2303_device);
}
 
 
module_init(pl2303_init);
module_exit(pl2303_exit);
 
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
 
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
 
/shark/trunk/drivers/usb/serial/usb-serial.c
1,1476 → 1,1477
/*
* USB Serial Converter driver
*
* Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This driver was originally based on the ACM driver by Armin Fuerst (which was
* based on a driver by Brad Keryan)
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (12/10/2002) gkh
* Split the ports off into their own struct device, and added a
* usb-serial bus driver.
*
* (11/19/2002) gkh
* removed a few #ifdefs for the generic code and cleaned up the failure
* logic in initialization.
*
* (10/02/2002) gkh
* moved the console code to console.c and out of this file.
*
* (06/05/2002) gkh
* moved location of startup() call in serial_probe() until after all
* of the port information and endpoints are initialized. This makes
* things easier for some drivers.
*
* (04/10/2002) gkh
* added serial_read_proc function which creates a
* /proc/tty/driver/usb-serial file.
*
* (03/27/2002) gkh
* Got USB serial console code working properly and merged into the main
* version of the tree. Thanks to Randy Dunlap for the initial version
* of this code, and for pushing me to finish it up.
* The USB serial console works with any usb serial driver device.
*
* (03/21/2002) gkh
* Moved all manipulation of port->open_count into the core. Now the
* individual driver's open and close functions are called only when the
* first open() and last close() is called. Making the drivers a bit
* smaller and simpler.
* Fixed a bug if a driver didn't have the owner field set.
*
* (02/26/2002) gkh
* Moved all locking into the main serial_* functions, instead of having
* the individual drivers have to grab the port semaphore. This should
* reduce races.
* Reworked the MOD_INC logic a bit to always increment and decrement, even
* if the generic driver is being used.
*
* (10/10/2001) gkh
* usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
* help prevent child drivers from accessing the device since it is now
* gone.
*
* (09/13/2001) gkh
* Moved generic driver initialize after we have registered with the USB
* core. Thanks to Randy Dunlap for pointing this problem out.
*
* (07/03/2001) gkh
* Fixed module paramater size. Thanks to John Brockmeyer for the pointer.
* Fixed vendor and product getting defined through the MODULE_PARM macro
* if the Generic driver wasn't compiled in.
* Fixed problem with generic_shutdown() not being called for drivers that
* don't have a shutdown() function.
*
* (06/06/2001) gkh
* added evil hack that is needed for the prolific pl2303 device due to the
* crazy way its endpoints are set up.
*
* (05/30/2001) gkh
* switched from using spinlock to a semaphore, which fixes lots of problems.
*
* (04/08/2001) gb
* Identify version on module load.
*
* 2001_02_05 gkh
* Fixed buffer overflows bug with the generic serial driver. Thanks to
* Todd Squires <squirest@ct0.com> for fixing this.
*
* (01/10/2001) gkh
* Fixed bug where the generic serial adaptor grabbed _any_ device that was
* offered to it.
*
* (12/12/2000) gkh
* Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
* moved them to the serial_open and serial_close functions.
* Also fixed bug with there not being a MOD_DEC for the generic driver
* (thanks to Gary Brubaker for finding this.)
*
* (11/29/2000) gkh
* Small NULL pointer initialization cleanup which saves a bit of disk image
*
* (11/01/2000) Adam J. Richter
* instead of using idVendor/idProduct pairs, usb serial drivers
* now identify their hardware interest with usb_device_id tables,
* which they usually have anyhow for use with MODULE_DEVICE_TABLE.
*
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
*
* (09/11/2000) gkh
* Removed DEBUG #ifdefs with call to usb_serial_debug_data
*
* (08/28/2000) gkh
* Added port_lock to port structure.
* Added locks for SMP safeness to generic driver
* Fixed the ability to open a generic device's port more than once.
*
* (07/23/2000) gkh
* Added bulk_out_endpointAddress to port structure.
*
* (07/19/2000) gkh, pberger, and borchers
* Modifications to allow usb-serial drivers to be modules.
*
* (07/03/2000) gkh
* Added more debugging to serial_ioctl call
*
* (06/25/2000) gkh
* Changed generic_write_bulk_callback to not call wake_up_interruptible
* directly, but to have port_softint do it at a safer time.
*
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
* (05/22/2000) gkh
* Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
* removed from the individual device source files.
*
* (05/03/2000) gkh
* Added the Digi Acceleport driver from Al Borchers and Peter Berger.
*
* (05/02/2000) gkh
* Changed devfs and tty register code to work properly now. This was based on
* the ACM driver changes by Vojtech Pavlik.
*
* (04/27/2000) Ryan VanderBijl
* Put calls to *_paranoia_checks into one function.
*
* (04/23/2000) gkh
* Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
* Moved when the startup code printed out the devices that are supported.
*
* (04/19/2000) gkh
* Added driver for ZyXEL omni.net lcd plus ISDN TA
* Made startup info message specify which drivers were compiled in.
*
* (04/03/2000) gkh
* Changed the probe process to remove the module unload races.
* Changed where the tty layer gets initialized to have devfs work nicer.
* Added initial devfs support.
*
* (03/26/2000) gkh
* Split driver up into device specific pieces.
*
* (03/19/2000) gkh
* Fixed oops that could happen when device was removed while a program
* was talking to the device.
* Removed the static urbs and now all urbs are created and destroyed
* dynamically.
* Reworked the internal interface. Now everything is based on the
* usb_serial_port structure instead of the larger usb_serial structure.
* This fixes the bug that a multiport device could not have more than
* one port open at one time.
*
* (03/17/2000) gkh
* Added config option for debugging messages.
* Added patch for keyspan pda from Brian Warner.
*
* (03/06/2000) gkh
* Added the keyspan pda code from Brian Warner <warner@lothar.com>
* Moved a bunch of the port specific stuff into its own structure. This
* is in anticipation of the true multiport devices (there's a bug if you
* try to access more than one port of any multiport device right now)
*
* (02/21/2000) gkh
* Made it so that any serial devices only have to specify which functions
* they want to overload from the generic function calls (great,
* inheritance in C, in a driver, just what I wanted...)
* Added support for set_termios and ioctl function calls. No drivers take
* advantage of this yet.
* Removed the #ifdef MODULE, now there is no module specific code.
* Cleaned up a few comments in usb-serial.h that were wrong (thanks again
* to Miles Lott).
* Small fix to get_free_serial.
*
* (02/14/2000) gkh
* Removed the Belkin and Peracom functionality from the driver due to
* the lack of support from the vendor, and me not wanting people to
* accidenatly buy the device, expecting it to work with Linux.
* Added read_bulk_callback and write_bulk_callback to the type structure
* for the needs of the FTDI and WhiteHEAT driver.
* Changed all reverences to FTDI to FTDI_SIO at the request of Bill
* Ryder.
* Changed the output urb size back to the max endpoint size to make
* the ftdi_sio driver have it easier, and due to the fact that it didn't
* really increase the speed any.
*
* (02/11/2000) gkh
* Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
* patch from Miles Lott (milos@insync.net).
* Fixed bug with not restoring the minor range that a device grabs, if
* the startup function fails (thanks Miles for finding this).
*
* (02/05/2000) gkh
* Added initial framework for the Keyspan PDA serial converter so that
* Brian Warner has a place to put his code.
* Made the ezusb specific functions generic enough that different
* devices can use them (whiteheat and keyspan_pda both need them).
* Split out a whole bunch of structure and other stuff to a separate
* usb-serial.h file.
* Made the Visor connection messages a little more understandable, now
* that Miles Lott (milos@insync.net) has gotten the Generic channel to
* work. Also made them always show up in the log file.
*
* (01/25/2000) gkh
* Added initial framework for FTDI serial converter so that Bill Ryder
* has a place to put his code.
* Added the vendor specific info from Handspring. Now we can print out
* informational debug messages as well as understand what is happening.
*
* (01/23/2000) gkh
* Fixed problem of crash when trying to open a port that didn't have a
* device assigned to it. Made the minor node finding a little smarter,
* now it looks to find a continuous space for the new device.
*
* (01/21/2000) gkh
* Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
* Fixed get_serial_by_minor which was all messed up for multi port
* devices. Fixed multi port problem for generic devices. Now the number
* of ports is determined by the number of bulk out endpoints for the
* generic device.
*
* (01/19/2000) gkh
* Removed lots of cruft that was around from the old (pre urb) driver
* interface.
* Made the serial_table dynamic. This should save lots of memory when
* the number of minor nodes goes up to 256.
* Added initial support for devices that have more than one port.
* Added more debugging comments for the Visor, and added a needed
* set_configuration call.
*
* (01/17/2000) gkh
* Fixed the WhiteHEAT firmware (my processing tool had a bug)
* and added new debug loader firmware for it.
* Removed the put_char function as it isn't really needed.
* Added visor startup commands as found by the Win98 dump.
*
* (01/13/2000) gkh
* Fixed the vendor id for the generic driver to the one I meant it to be.
*
* (01/12/2000) gkh
* Forget the version numbering...that's pretty useless...
* Made the driver able to be compiled so that the user can select which
* converter they want to use. This allows people who only want the Visor
* support to not pay the memory size price of the WhiteHEAT.
* Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
* grabbed the root hub. Not good.
*
* version 0.4.0 (01/10/2000) gkh
* Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
* device. Added startup function to allow firmware to be downloaded to
* a device if it needs to be.
* Added firmware download logic to the WhiteHEAT device.
* Started to add #defines to split up the different drivers for potential
* configuration option.
*
* version 0.3.1 (12/30/99) gkh
* Fixed problems with urb for bulk out.
* Added initial support for multiple sets of endpoints. This enables
* the Handspring Visor to be attached successfully. Only the first
* bulk in / bulk out endpoint pair is being used right now.
*
* version 0.3.0 (12/27/99) gkh
* Added initial support for the Handspring Visor based on a patch from
* Miles Lott (milos@sneety.insync.net)
* Cleaned up the code a bunch and converted over to using urbs only.
*
* version 0.2.3 (12/21/99) gkh
* Added initial support for the Connect Tech WhiteHEAT converter.
* Incremented the number of ports in expectation of getting the
* WhiteHEAT to work properly (4 ports per connection).
* Added notification on insertion and removal of what port the
* device is/was connected to (and what kind of device it was).
*
* version 0.2.2 (12/16/99) gkh
* Changed major number to the new allocated number. We're legal now!
*
* version 0.2.1 (12/14/99) gkh
* Fixed bug that happens when device node is opened when there isn't a
* device attached to it. Thanks to marek@webdesign.no for noticing this.
*
* version 0.2.0 (11/10/99) gkh
* Split up internals to make it easier to add different types of serial
* converters to the code.
* Added a "generic" driver that gets it's vendor and product id
* from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
* for the idea and sample code (from the usb scanner driver.)
* Cleared up any licensing questions by releasing it under the GNU GPL.
*
* version 0.1.2 (10/25/99) gkh
* Fixed bug in detecting device.
*
* version 0.1.1 (10/05/99) gkh
* Changed the major number to not conflict with anything else.
*
* version 0.1 (09/28/99) gkh
* Can recognize the two different devices and start up a read from
* device when asked to. Writes also work. No control signals yet, this
* all is vendor specific data (i.e. no spec), also no control for
* different baud rates or other bit settings.
* Currently we are using the same devid as the acm driver. This needs
* to change.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
 
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
#include "pl2303.h"
 
/*
* Version Information
*/
#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
 
 
#ifdef CONFIG_USB_SERIAL_GENERIC
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42},
{}
};
 
#endif /* CONFIG_USB_SERIAL_GENERIC */
 
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.owner = THIS_MODULE,
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
#ifdef CONFIG_USB_SERIAL_GENERIC
.id_table = generic_serial_ids,
#endif
};
 
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
the MODULE_DEVICE_TABLE declarations in each serial driver
cause the "hotplug" program to pull in whatever module is necessary
via modprobe, and modprobe will load usbserial because the serial
drivers depend on it.
*/
 
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list);
 
 
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial = serial_table[index];
 
if (serial)
kobject_get (&serial->kobj);
return serial;
}
 
static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
{
unsigned int i, j;
int good_spot;
 
dbg("%s %d", __FUNCTION__, num_ports);
 
*minor = 0;
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
 
good_spot = 1;
for (j = 1; j <= num_ports-1; ++j)
if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) {
good_spot = 0;
i += j;
break;
}
if (good_spot == 0)
continue;
serial->magic = USB_SERIAL_MAGIC;
*minor = i;
dbg("%s - minor base = %d", __FUNCTION__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
}
return NULL;
}
 
static void return_serial (struct usb_serial *serial)
{
int i;
 
dbg("%s", __FUNCTION__);
 
if (serial == NULL)
return;
 
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
 
return;
}
 
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
/*static*/ int serial_open (struct tty_struct *tty, struct file * filp)
{
struct usb_serial *serial;
struct usb_serial_port *port;
unsigned int portNumber;
int retval = 0;
dbg("%s", __FUNCTION__);
 
/* initialize the pointer incase something fails */
tty->driver_data = NULL;
 
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index);
 
if (serial_paranoia_check (serial, __FUNCTION__))
return -ENODEV;
 
/* set up our port structure making the tty driver remember our port object, and us it */
portNumber = tty->index - serial->minor;
port = serial->port[portNumber];
tty->driver_data = port;
 
port->tty = tty;
/* lock this module before we call it,
this may, which means we must bail out, safe because we are called with BKL held */
if (!try_module_get(serial->type->owner)) {
retval = -ENODEV;
goto bailout;
}
 
++port->open_count;
if (port->open_count == 1) {
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
if (retval) {
port->open_count = 0;
module_put(serial->type->owner);
kobject_put(&serial->kobj);
}
}
bailout:
return retval;
}
 
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
--port->open_count;
if (port->open_count <= 0) {
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
port->open_count = 0;
 
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
}
 
module_put(port->serial->type->owner);
kobject_put(&port->serial->kobj);
}
 
/*static*/ int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
if (!port->open_count) {
dbg("%s - port not opened", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->write(port, from_user, buf, count);
 
exit:
return retval;
}
 
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->write_room(port);
 
exit:
return retval;
}
 
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s = port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->chars_in_buffer(port);
 
exit:
return retval;
}
 
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg ("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
if (serial->type->throttle)
serial->type->throttle(port);
 
exit:
;
}
 
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle)
serial->type->unthrottle(port);
 
exit:
;
}
 
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -ENODEV;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
if (!port->open_count) {
dbg ("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->ioctl)
retval = serial->type->ioctl(port, file, cmd, arg);
else
retval = -ENOIOCTLCMD;
 
exit:
return retval;
}
 
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->set_termios)
serial->type->set_termios(port, old);
 
exit:
;
}
 
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->break_ctl)
serial->type->break_ctl(port, break_state);
 
exit:
;
}
 
static void serial_shutdown (struct usb_serial *serial)
{
dbg ("%s", __FUNCTION__);
 
serial->type->shutdown(serial);
}
 
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct usb_serial *serial;
int length = 0;
int i;
off_t begin = 0;
char tmp[40];
 
dbg("%s", __FUNCTION__);
length += sprintf26 (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION);
for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
serial = usb_serial_get_by_index(i);
if (serial == NULL)
continue;
 
length += sprintf26 (page+length, "%d:", i);
if (serial->type->owner)
length += sprintf26 (page+length, " module:%s", module_name(serial->type->owner));
length += sprintf26 (page+length, " name:\"%s\"", serial->type->name);
length += sprintf26 (page+length, " vendor:%04x product:%04x", serial->vendor, serial->product);
length += sprintf26 (page+length, " num_ports:%d", serial->num_ports);
length += sprintf26 (page+length, " port:%d", i - serial->minor + 1);
 
usb_make_path(serial->dev, tmp, sizeof(tmp));
length += sprintf26 (page+length, " path:%s", tmp);
length += sprintf26 (page+length, "\n");
if ((length + begin) > (off + count))
goto done;
if ((length + begin) < off) {
begin += length;
length = 0;
}
kobject_put(&serial->kobj);
}
*eof = 1;
done:
if (off >= (length + begin))
return 0;
*start = page + (off-begin);
return ((count < begin+length-off) ? count : begin+length-off);
}
 
static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
goto exit;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
if (serial->type->tiocmget)
return serial->type->tiocmget(port, file);
 
exit:
return -EINVAL;
}
 
static int serial_tiocmset (struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
goto exit;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
if (serial->type->tiocmset)
return serial->type->tiocmset(port, file, set, clear);
 
exit:
return -EINVAL;
}
 
void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial *serial;
struct tty_struct *tty;
 
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port)
return;
 
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
 
tty = port->tty;
if (!tty)
return;
 
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg("%s - write wakeup call.", __FUNCTION__);
(tty->ldisc.write_wakeup)(tty);
}
 
wake_up_interruptible(&tty->write_wait);
}
 
static void destroy_serial (struct kobject *kobj)
{
struct usb_serial *serial;
struct usb_serial_port *port;
int i;
 
dbg ("%s - %s", __FUNCTION__, kobj->name);
 
serial = to_usb_serial(kobj);
serial_shutdown (serial);
 
/* return the minor range that this device had */
return_serial(serial);
 
for (i = 0; i < serial->num_ports; ++i)
serial->port[i]->open_count = 0;
 
/* the ports are cleaned up and released in port_release() */
for (i = 0; i < serial->num_ports; ++i)
if (serial->port[i]->dev.parent != NULL) {
device_unregister(&serial->port[i]->dev);
serial->port[i] = NULL;
}
 
/* If this is a "fake" port, we have to clean it up here, as it will
* not get cleaned up in port_release() as it was never registered with
* the driver core */
if (serial->num_ports < serial->num_port_pointers) {
for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
}
}
 
usb_put_dev(serial->dev);
 
/* free up any memory that we allocated */
kfree (serial);
}
 
static struct kobj_type usb_serial_kobj_type = {
.release = destroy_serial,
};
 
static void port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
 
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port);
}
 
static struct usb_serial * create_serial (struct usb_device *dev,
struct usb_interface *interface,
struct usb_serial_device_type *type)
{
struct usb_serial *serial;
 
serial = kmalloc (sizeof (*serial), GFP_KERNEL);
if (!serial) {
dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
return NULL;
}
memset (serial, 0, sizeof(*serial));
serial->dev = usb_get_dev(dev);
serial->type = type;
serial->interface = interface;
serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct;
 
/* initialize the kobject portion of the usb_device */
kobject_init(&serial->kobj);
serial->kobj.ktype = &usb_serial_kobj_type;
 
return serial;
}
 
int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (interface);
struct usb_serial *serial = NULL;
struct usb_serial_port *port;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_device_type *type = NULL;
struct list_head *tmp;
int retval;
int found;
int minor;
int buffer_size;
int i;
int num_interrupt_in = 0;
int num_bulk_in = 0;
int num_bulk_out = 0;
int num_ports = 0;
int max_endpoints;
const struct usb_device_id *id_pattern = NULL;
 
/* loop through our list of known serial converters, and see if this
device matches. */
found = 0;
list_for_each (tmp, &usb_serial_driver_list) {
type = list_entry(tmp, struct usb_serial_device_type, driver_list);
id_pattern = usb_match_id(interface, type->id_table);
if (id_pattern != NULL) {
dbg("descriptor matches");
found = 1;
break;
}
}
if (!found) {
/* no match */
dbg("none matched");
return -ENODEV;
}
serial = create_serial (dev, interface, type);
if (!serial) {
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
return -ENODEV;
}
 
/* if this device type has a probe function, call it */
if (type->probe) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
retval = type->probe (serial, id_pattern);
module_put(type->owner);
 
if (retval) {
dbg ("sub driver rejected device");
kfree (serial);
return retval;
}
}
 
/* descriptor matches, let's find the endpoints needed */
/* check out the endpoints */
iface_desc = &interface->altsetting[0];
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */
dbg("found bulk in");
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
 
if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk out endpoint */
dbg("found bulk out");
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
}
 
#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
/* BEGIN HORRIBLE HACK FOR PL2303 */
/* this is needed due to the looney way its endpoints are set up */
if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
(dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
(dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
iface_desc = &dev->actconfig->interface[0]->altsetting[0];
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in for Prolific device on separate interface");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
}
}
 
/* Now make sure the PL-2303 is configured correctly.
* If not, give up now and hope this hack will work
* properly during a later invocation of usb_serial_probe
*/
if (num_bulk_in == 0 || num_bulk_out == 0) {
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree (serial);
return -ENODEV;
}
}
/* END HORRIBLE HACK FOR PL2303 */
#endif
 
/* found all that we need */
dev_info(&interface->dev, "%s converter detected\n", type->name);
 
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
if (num_ports == 0) {
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
kfree (serial);
return -EIO;
}
}
#endif
if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
num_ports = type->calc_num_ports (serial);
module_put(type->owner);
}
if (!num_ports)
num_ports = type->num_ports;
}
 
if (get_free_serial (serial, num_ports, &minor) == NULL) {
dev_err(&interface->dev, "No more free serial devices\n");
kfree (serial);
return -ENOMEM;
}
 
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
 
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
goto probe_error;
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
 
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
endpoint = bulk_in_endpoint[i];
port = serial->port[i];
port->read_urb = usb_alloc_urb (0, GFP_KERNEL);
if (!port->read_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
 
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_in_buffer) {
dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");
goto probe_error;
}
usb_fill_bulk_urb (port->read_urb, dev,
usb_rcvbulkpipe (dev,
endpoint->bEndpointAddress),
port->bulk_in_buffer, buffer_size,
serial->type->read_bulk_callback,
port);
}
 
for (i = 0; i < num_bulk_out; ++i) {
endpoint = bulk_out_endpoint[i];
port = serial->port[i];
port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->write_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_out_buffer) {
dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");
goto probe_error;
}
usb_fill_bulk_urb (port->write_urb, dev,
usb_sndbulkpipe (dev,
endpoint->bEndpointAddress),
port->bulk_out_buffer, buffer_size,
serial->type->write_bulk_callback,
port);
}
 
for (i = 0; i < num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i];
port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_in_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->interrupt_in_buffer) {
dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
goto probe_error;
}
usb_fill_int_urb (port->interrupt_in_urb, dev,
usb_rcvintpipe (dev,
endpoint->bEndpointAddress),
port->interrupt_in_buffer, buffer_size,
serial->type->read_int_callback, port,
endpoint->bInterval);
}
 
/* if this device type has an attach function, call it */
if (type->attach) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
goto probe_error;
}
retval = type->attach (serial);
module_put(type->owner);
if (retval < 0)
goto probe_error;
if (retval > 0) {
/* quietly accept this device, but don't bind to a serial port
* as it's about to disappear */
goto exit;
}
}
 
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
port->dev.parent = &interface->dev;
port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type;
port->dev.release = &port_release;
 
snprintf26(&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
device_register (&port->dev);
}
 
usb_serial_console_init (debug, minor);
 
exit:
/* success */
usb_set_intfdata (interface, serial);
return 0;
 
probe_error:
for (i = 0; i < num_bulk_in; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb)
usb_free_urb (port->read_urb);
kfree(port->bulk_in_buffer);
}
for (i = 0; i < num_bulk_out; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->write_urb)
usb_free_urb (port->write_urb);
kfree(port->bulk_out_buffer);
}
for (i = 0; i < num_interrupt_in; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->interrupt_in_urb)
usb_free_urb (port->interrupt_in_urb);
kfree(port->interrupt_in_buffer);
}
 
/* return the minor range that this device had */
return_serial (serial);
 
/* free up any memory that we allocated */
for (i = 0; i < serial->num_port_pointers; ++i)
kfree(serial->port[i]);
kfree (serial);
return -EIO;
}
 
void usb_serial_disconnect(struct usb_interface *interface)
{
struct usb_serial *serial = usb_get_intfdata (interface);
struct device *dev = &interface->dev;
 
dbg ("%s", __FUNCTION__);
 
usb_set_intfdata (interface, NULL);
if (serial) {
/* let the last holder of this object
* cause it to be cleaned up */
kobject_put (&serial->kobj);
}
dev_info(dev, "device disconnected\n");
}
 
static struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
.write = serial_write,
.write_room = serial_write_room,
.ioctl = serial_ioctl,
.set_termios = serial_set_termios,
.throttle = serial_throttle,
.unthrottle = serial_unthrottle,
.break_ctl = serial_break,
.chars_in_buffer = serial_chars_in_buffer,
.read_proc = serial_read_proc,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
};
 
struct tty_driver *usb_serial_tty_driver;
 
/*static*/ int __init usb_serial_init(void)
{
int i;
int result = 0;
 
usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
 
/* Initialize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
 
bus_register(&usb_serial_bus_type);
 
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit;
}
 
usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->devfs_name = "usb/tts/";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
usb_serial_tty_driver->minor_start = 0;
usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(usb_serial_tty_driver, &serial_ops);
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
err("%s - tty_register_driver failed", __FUNCTION__);
goto exit_generic;
}
 
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
err("%s - usb_register failed", __FUNCTION__);
goto exit_tty;
}
 
info(DRIVER_DESC " " DRIVER_VERSION);
 
return result;
 
exit_tty:
tty_unregister_driver(usb_serial_tty_driver);
 
exit_generic:
usb_serial_generic_deregister();
 
exit:
err ("%s - returning with error %d", __FUNCTION__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
 
 
/*static*/ void __exit usb_serial_exit(void)
{
usb_serial_console_exit();
 
usb_serial_generic_deregister();
 
usb_deregister(&usb_serial_driver);
tty_unregister_driver(usb_serial_tty_driver);
put_tty_driver(usb_serial_tty_driver);
bus_unregister(&usb_serial_bus_type);
}
 
 
module_init(usb_serial_init);
module_exit(usb_serial_exit);
 
#define set_to_generic_if_null(type, function) \
do { \
if (!type->function) { \
type->function = usb_serial_generic_##function; \
dbg("Had to override the " #function \
" usb serial operation with the generic one.");\
} \
} while (0)
 
static void fixup_generic(struct usb_serial_device_type *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
}
 
int usb_serial_register(struct usb_serial_device_type *new_device)
{
int retval;
 
fixup_generic(new_device);
 
/* Add this device to our list of devices */
list_add(&new_device->driver_list, &usb_serial_driver_list);
 
retval = usb_serial_bus_register (new_device);
 
if (retval)
goto error;
 
info("USB Serial support registered for %s", new_device->name);
 
return retval;
error:
err("problem %d when registering driver %s", retval, new_device->name);
list_del(&new_device->driver_list);
 
return retval;
}
 
 
void usb_serial_deregister(struct usb_serial_device_type *device)
{
struct usb_serial *serial;
int i;
 
info("USB Serial deregistering driver %s", device->name);
 
/* clear out the serial_table if the device is attached to a port */
for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial = serial_table[i];
if ((serial != NULL) && (serial->type == device)) {
usb_driver_release_interface (&usb_serial_driver, serial->interface);
usb_serial_disconnect (serial->interface);
}
}
 
list_del(&device->driver_list);
usb_serial_bus_deregister (device);
}
 
 
 
/* If the usb-serial core is built into the core, the usb-serial drivers
need these symbols to load properly as modules. */
EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
EXPORT_SYMBOL(usb_serial_probe);
EXPORT_SYMBOL(usb_serial_disconnect);
EXPORT_SYMBOL(usb_serial_port_softint);
 
 
/* Module information */
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
 
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
/*
* USB Serial Converter driver
*
* Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This driver was originally based on the ACM driver by Armin Fuerst (which was
* based on a driver by Brad Keryan)
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* (12/10/2002) gkh
* Split the ports off into their own struct device, and added a
* usb-serial bus driver.
*
* (11/19/2002) gkh
* removed a few #ifdefs for the generic code and cleaned up the failure
* logic in initialization.
*
* (10/02/2002) gkh
* moved the console code to console.c and out of this file.
*
* (06/05/2002) gkh
* moved location of startup() call in serial_probe() until after all
* of the port information and endpoints are initialized. This makes
* things easier for some drivers.
*
* (04/10/2002) gkh
* added serial_read_proc function which creates a
* /proc/tty/driver/usb-serial file.
*
* (03/27/2002) gkh
* Got USB serial console code working properly and merged into the main
* version of the tree. Thanks to Randy Dunlap for the initial version
* of this code, and for pushing me to finish it up.
* The USB serial console works with any usb serial driver device.
*
* (03/21/2002) gkh
* Moved all manipulation of port->open_count into the core. Now the
* individual driver's open and close functions are called only when the
* first open() and last close() is called. Making the drivers a bit
* smaller and simpler.
* Fixed a bug if a driver didn't have the owner field set.
*
* (02/26/2002) gkh
* Moved all locking into the main serial_* functions, instead of having
* the individual drivers have to grab the port semaphore. This should
* reduce races.
* Reworked the MOD_INC logic a bit to always increment and decrement, even
* if the generic driver is being used.
*
* (10/10/2001) gkh
* usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
* help prevent child drivers from accessing the device since it is now
* gone.
*
* (09/13/2001) gkh
* Moved generic driver initialize after we have registered with the USB
* core. Thanks to Randy Dunlap for pointing this problem out.
*
* (07/03/2001) gkh
* Fixed module paramater size. Thanks to John Brockmeyer for the pointer.
* Fixed vendor and product getting defined through the MODULE_PARM macro
* if the Generic driver wasn't compiled in.
* Fixed problem with generic_shutdown() not being called for drivers that
* don't have a shutdown() function.
*
* (06/06/2001) gkh
* added evil hack that is needed for the prolific pl2303 device due to the
* crazy way its endpoints are set up.
*
* (05/30/2001) gkh
* switched from using spinlock to a semaphore, which fixes lots of problems.
*
* (04/08/2001) gb
* Identify version on module load.
*
* 2001_02_05 gkh
* Fixed buffer overflows bug with the generic serial driver. Thanks to
* Todd Squires <squirest@ct0.com> for fixing this.
*
* (01/10/2001) gkh
* Fixed bug where the generic serial adaptor grabbed _any_ device that was
* offered to it.
*
* (12/12/2000) gkh
* Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
* moved them to the serial_open and serial_close functions.
* Also fixed bug with there not being a MOD_DEC for the generic driver
* (thanks to Gary Brubaker for finding this.)
*
* (11/29/2000) gkh
* Small NULL pointer initialization cleanup which saves a bit of disk image
*
* (11/01/2000) Adam J. Richter
* instead of using idVendor/idProduct pairs, usb serial drivers
* now identify their hardware interest with usb_device_id tables,
* which they usually have anyhow for use with MODULE_DEVICE_TABLE.
*
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
*
* (09/11/2000) gkh
* Removed DEBUG #ifdefs with call to usb_serial_debug_data
*
* (08/28/2000) gkh
* Added port_lock to port structure.
* Added locks for SMP safeness to generic driver
* Fixed the ability to open a generic device's port more than once.
*
* (07/23/2000) gkh
* Added bulk_out_endpointAddress to port structure.
*
* (07/19/2000) gkh, pberger, and borchers
* Modifications to allow usb-serial drivers to be modules.
*
* (07/03/2000) gkh
* Added more debugging to serial_ioctl call
*
* (06/25/2000) gkh
* Changed generic_write_bulk_callback to not call wake_up_interruptible
* directly, but to have port_softint do it at a safer time.
*
* (06/23/2000) gkh
* Cleaned up debugging statements in a quest to find UHCI timeout bug.
*
* (05/22/2000) gkh
* Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
* removed from the individual device source files.
*
* (05/03/2000) gkh
* Added the Digi Acceleport driver from Al Borchers and Peter Berger.
*
* (05/02/2000) gkh
* Changed devfs and tty register code to work properly now. This was based on
* the ACM driver changes by Vojtech Pavlik.
*
* (04/27/2000) Ryan VanderBijl
* Put calls to *_paranoia_checks into one function.
*
* (04/23/2000) gkh
* Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
* Moved when the startup code printed out the devices that are supported.
*
* (04/19/2000) gkh
* Added driver for ZyXEL omni.net lcd plus ISDN TA
* Made startup info message specify which drivers were compiled in.
*
* (04/03/2000) gkh
* Changed the probe process to remove the module unload races.
* Changed where the tty layer gets initialized to have devfs work nicer.
* Added initial devfs support.
*
* (03/26/2000) gkh
* Split driver up into device specific pieces.
*
* (03/19/2000) gkh
* Fixed oops that could happen when device was removed while a program
* was talking to the device.
* Removed the static urbs and now all urbs are created and destroyed
* dynamically.
* Reworked the internal interface. Now everything is based on the
* usb_serial_port structure instead of the larger usb_serial structure.
* This fixes the bug that a multiport device could not have more than
* one port open at one time.
*
* (03/17/2000) gkh
* Added config option for debugging messages.
* Added patch for keyspan pda from Brian Warner.
*
* (03/06/2000) gkh
* Added the keyspan pda code from Brian Warner <warner@lothar.com>
* Moved a bunch of the port specific stuff into its own structure. This
* is in anticipation of the true multiport devices (there's a bug if you
* try to access more than one port of any multiport device right now)
*
* (02/21/2000) gkh
* Made it so that any serial devices only have to specify which functions
* they want to overload from the generic function calls (great,
* inheritance in C, in a driver, just what I wanted...)
* Added support for set_termios and ioctl function calls. No drivers take
* advantage of this yet.
* Removed the #ifdef MODULE, now there is no module specific code.
* Cleaned up a few comments in usb-serial.h that were wrong (thanks again
* to Miles Lott).
* Small fix to get_free_serial.
*
* (02/14/2000) gkh
* Removed the Belkin and Peracom functionality from the driver due to
* the lack of support from the vendor, and me not wanting people to
* accidenatly buy the device, expecting it to work with Linux.
* Added read_bulk_callback and write_bulk_callback to the type structure
* for the needs of the FTDI and WhiteHEAT driver.
* Changed all reverences to FTDI to FTDI_SIO at the request of Bill
* Ryder.
* Changed the output urb size back to the max endpoint size to make
* the ftdi_sio driver have it easier, and due to the fact that it didn't
* really increase the speed any.
*
* (02/11/2000) gkh
* Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
* patch from Miles Lott (milos@insync.net).
* Fixed bug with not restoring the minor range that a device grabs, if
* the startup function fails (thanks Miles for finding this).
*
* (02/05/2000) gkh
* Added initial framework for the Keyspan PDA serial converter so that
* Brian Warner has a place to put his code.
* Made the ezusb specific functions generic enough that different
* devices can use them (whiteheat and keyspan_pda both need them).
* Split out a whole bunch of structure and other stuff to a separate
* usb-serial.h file.
* Made the Visor connection messages a little more understandable, now
* that Miles Lott (milos@insync.net) has gotten the Generic channel to
* work. Also made them always show up in the log file.
*
* (01/25/2000) gkh
* Added initial framework for FTDI serial converter so that Bill Ryder
* has a place to put his code.
* Added the vendor specific info from Handspring. Now we can print out
* informational debug messages as well as understand what is happening.
*
* (01/23/2000) gkh
* Fixed problem of crash when trying to open a port that didn't have a
* device assigned to it. Made the minor node finding a little smarter,
* now it looks to find a continuous space for the new device.
*
* (01/21/2000) gkh
* Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
* Fixed get_serial_by_minor which was all messed up for multi port
* devices. Fixed multi port problem for generic devices. Now the number
* of ports is determined by the number of bulk out endpoints for the
* generic device.
*
* (01/19/2000) gkh
* Removed lots of cruft that was around from the old (pre urb) driver
* interface.
* Made the serial_table dynamic. This should save lots of memory when
* the number of minor nodes goes up to 256.
* Added initial support for devices that have more than one port.
* Added more debugging comments for the Visor, and added a needed
* set_configuration call.
*
* (01/17/2000) gkh
* Fixed the WhiteHEAT firmware (my processing tool had a bug)
* and added new debug loader firmware for it.
* Removed the put_char function as it isn't really needed.
* Added visor startup commands as found by the Win98 dump.
*
* (01/13/2000) gkh
* Fixed the vendor id for the generic driver to the one I meant it to be.
*
* (01/12/2000) gkh
* Forget the version numbering...that's pretty useless...
* Made the driver able to be compiled so that the user can select which
* converter they want to use. This allows people who only want the Visor
* support to not pay the memory size price of the WhiteHEAT.
* Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
* grabbed the root hub. Not good.
*
* version 0.4.0 (01/10/2000) gkh
* Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
* device. Added startup function to allow firmware to be downloaded to
* a device if it needs to be.
* Added firmware download logic to the WhiteHEAT device.
* Started to add #defines to split up the different drivers for potential
* configuration option.
*
* version 0.3.1 (12/30/99) gkh
* Fixed problems with urb for bulk out.
* Added initial support for multiple sets of endpoints. This enables
* the Handspring Visor to be attached successfully. Only the first
* bulk in / bulk out endpoint pair is being used right now.
*
* version 0.3.0 (12/27/99) gkh
* Added initial support for the Handspring Visor based on a patch from
* Miles Lott (milos@sneety.insync.net)
* Cleaned up the code a bunch and converted over to using urbs only.
*
* version 0.2.3 (12/21/99) gkh
* Added initial support for the Connect Tech WhiteHEAT converter.
* Incremented the number of ports in expectation of getting the
* WhiteHEAT to work properly (4 ports per connection).
* Added notification on insertion and removal of what port the
* device is/was connected to (and what kind of device it was).
*
* version 0.2.2 (12/16/99) gkh
* Changed major number to the new allocated number. We're legal now!
*
* version 0.2.1 (12/14/99) gkh
* Fixed bug that happens when device node is opened when there isn't a
* device attached to it. Thanks to marek@webdesign.no for noticing this.
*
* version 0.2.0 (11/10/99) gkh
* Split up internals to make it easier to add different types of serial
* converters to the code.
* Added a "generic" driver that gets it's vendor and product id
* from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
* for the idea and sample code (from the usb scanner driver.)
* Cleared up any licensing questions by releasing it under the GNU GPL.
*
* version 0.1.2 (10/25/99) gkh
* Fixed bug in detecting device.
*
* version 0.1.1 (10/05/99) gkh
* Changed the major number to not conflict with anything else.
*
* version 0.1 (09/28/99) gkh
* Can recognize the two different devices and start up a read from
* device when asked to. Writes also work. No control signals yet, this
* all is vendor specific data (i.e. no spec), also no control for
* different baud rates or other bit settings.
* Currently we are using the same devid as the acm driver. This needs
* to change.
*
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
 
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
#include "pl2303.h"
 
/*
* Version Information
*/
#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
 
 
#ifdef CONFIG_USB_SERIAL_GENERIC
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42},
{}
};
 
#endif /* CONFIG_USB_SERIAL_GENERIC */
 
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.owner = THIS_MODULE,
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
#ifdef CONFIG_USB_SERIAL_GENERIC
.id_table = generic_serial_ids,
#endif
};
 
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
the MODULE_DEVICE_TABLE declarations in each serial driver
cause the "hotplug" program to pull in whatever module is necessary
via modprobe, and modprobe will load usbserial because the serial
drivers depend on it.
*/
 
static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; /* initially all NULL */
static LIST_HEAD(usb_serial_driver_list);
 
 
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial = serial_table[index];
 
if (serial)
kobject_get (&serial->kobj);
return serial;
}
 
static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
{
unsigned int i, j;
int good_spot;
 
dbg("%s %d", __FUNCTION__, num_ports);
 
*minor = 0;
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
if (serial_table[i])
continue;
 
good_spot = 1;
for (j = 1; j <= num_ports-1; ++j)
if ((serial_table[i+j]) || (i+j >= SERIAL_TTY_MINORS)) {
good_spot = 0;
i += j;
break;
}
if (good_spot == 0)
continue;
serial->magic = USB_SERIAL_MAGIC;
*minor = i;
dbg("%s - minor base = %d", __FUNCTION__, *minor);
for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
serial_table[i] = serial;
return serial;
}
return NULL;
}
 
static void return_serial (struct usb_serial *serial)
{
int i;
 
dbg("%s", __FUNCTION__);
printk("Returning serial %d ports %d\n", serial->minor, serial->num_ports);
 
if (serial == NULL)
return;
 
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
 
return;
}
 
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
/*static*/ int serial_open (struct tty_struct *tty, struct file * filp)
{
struct usb_serial *serial;
struct usb_serial_port *port;
unsigned int portNumber;
int retval = 0;
dbg("%s", __FUNCTION__);
 
/* initialize the pointer incase something fails */
tty->driver_data = NULL;
 
/* get the serial object associated with this tty pointer */
serial = usb_serial_get_by_index(tty->index);
 
if (serial_paranoia_check (serial, __FUNCTION__))
return -ENODEV;
 
/* set up our port structure making the tty driver remember our port object, and us it */
portNumber = tty->index - serial->minor;
port = serial->port[portNumber];
tty->driver_data = port;
 
port->tty = tty;
/* lock this module before we call it,
this may, which means we must bail out, safe because we are called with BKL held */
if (!try_module_get(serial->type->owner)) {
retval = -ENODEV;
goto bailout;
}
 
++port->open_count;
if (port->open_count == 1) {
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
if (retval) {
port->open_count = 0;
module_put(serial->type->owner);
kobject_put(&serial->kobj);
}
}
bailout:
return retval;
}
 
static void serial_close(struct tty_struct *tty, struct file * filp)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
--port->open_count;
if (port->open_count <= 0) {
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
port->open_count = 0;
 
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
}
 
module_put(port->serial->type->owner);
kobject_put(&port->serial->kobj);
}
 
/*static*/ int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
if (!port->open_count) {
dbg("%s - port not opened", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->write(port, from_user, buf, count);
 
exit:
return retval;
}
 
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->write_room(port);
 
exit:
return retval;
}
 
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -EINVAL;
 
if (!serial)
return -ENODEV;
 
dbg("%s = port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
retval = serial->type->chars_in_buffer(port);
 
exit:
return retval;
}
 
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg ("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
if (serial->type->throttle)
serial->type->throttle(port);
 
exit:
;
}
 
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function */
if (serial->type->unthrottle)
serial->type->unthrottle(port);
 
exit:
;
}
 
static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
int retval = -ENODEV;
 
if (!serial)
return -ENODEV;
 
dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd);
 
if (!port->open_count) {
dbg ("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->ioctl)
retval = serial->type->ioctl(port, file, cmd, arg);
else
retval = -ENOIOCTLCMD;
 
exit:
return retval;
}
 
static void serial_set_termios (struct tty_struct *tty, struct termios * old)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->set_termios)
serial->type->set_termios(port, old);
 
exit:
;
}
 
static void serial_break (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
return;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
/* pass on to the driver specific version of this function if it is available */
if (serial->type->break_ctl)
serial->type->break_ctl(port, break_state);
 
exit:
;
}
 
static void serial_shutdown (struct usb_serial *serial)
{
dbg ("%s", __FUNCTION__);
 
serial->type->shutdown(serial);
}
 
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
{
struct usb_serial *serial;
int length = 0;
int i;
off_t begin = 0;
char tmp[40];
 
dbg("%s", __FUNCTION__);
length += sprintf26 (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION);
for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
serial = usb_serial_get_by_index(i);
if (serial == NULL)
continue;
 
length += sprintf26 (page+length, "%d:", i);
if (serial->type->owner)
length += sprintf26 (page+length, " module:%s", module_name(serial->type->owner));
length += sprintf26 (page+length, " name:\"%s\"", serial->type->name);
length += sprintf26 (page+length, " vendor:%04x product:%04x", serial->vendor, serial->product);
length += sprintf26 (page+length, " num_ports:%d", serial->num_ports);
length += sprintf26 (page+length, " port:%d", i - serial->minor + 1);
 
usb_make_path(serial->dev, tmp, sizeof(tmp));
length += sprintf26 (page+length, " path:%s", tmp);
length += sprintf26 (page+length, "\n");
if ((length + begin) > (off + count))
goto done;
if ((length + begin) < off) {
begin += length;
length = 0;
}
kobject_put(&serial->kobj);
}
*eof = 1;
done:
if (off >= (length + begin))
return 0;
*start = page + (off-begin);
return ((count < begin+length-off) ? count : begin+length-off);
}
 
static int serial_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
goto exit;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
if (serial->type->tiocmget)
return serial->type->tiocmget(port, file);
 
exit:
return -EINVAL;
}
 
static int serial_tiocmset (struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 
if (!serial)
goto exit;
 
dbg("%s - port %d", __FUNCTION__, port->number);
 
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
goto exit;
}
 
if (serial->type->tiocmset)
return serial->type->tiocmset(port, file, set, clear);
 
exit:
return -EINVAL;
}
 
void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = (struct usb_serial_port *)private;
struct usb_serial *serial;
struct tty_struct *tty;
 
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port)
return;
 
serial = get_usb_serial (port, __FUNCTION__);
if (!serial)
return;
 
tty = port->tty;
if (!tty)
return;
 
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
dbg("%s - write wakeup call.", __FUNCTION__);
(tty->ldisc.write_wakeup)(tty);
}
 
wake_up_interruptible(&tty->write_wait);
}
 
static void destroy_serial (struct kobject *kobj)
{
struct usb_serial *serial;
struct usb_serial_port *port;
int i;
 
dbg ("%s - %s", __FUNCTION__, kobj->name);
 
serial = to_usb_serial(kobj);
serial_shutdown (serial);
 
/* return the minor range that this device had */
return_serial(serial);
 
for (i = 0; i < serial->num_ports; ++i)
serial->port[i]->open_count = 0;
 
/* the ports are cleaned up and released in port_release() */
for (i = 0; i < serial->num_ports; ++i)
if (serial->port[i]->dev.parent != NULL) {
device_unregister(&serial->port[i]->dev);
serial->port[i] = NULL;
}
 
/* If this is a "fake" port, we have to clean it up here, as it will
* not get cleaned up in port_release() as it was never registered with
* the driver core */
if (serial->num_ports < serial->num_port_pointers) {
for (i = serial->num_ports; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
}
}
 
usb_put_dev(serial->dev);
 
/* free up any memory that we allocated */
kfree (serial);
}
 
static struct kobj_type usb_serial_kobj_type = {
.release = destroy_serial,
};
 
static void port_release(struct device *dev)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
 
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
if (port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if (port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if (port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port);
}
 
static struct usb_serial * create_serial (struct usb_device *dev,
struct usb_interface *interface,
struct usb_serial_device_type *type)
{
struct usb_serial *serial;
 
serial = kmalloc (sizeof (*serial), GFP_KERNEL);
if (!serial) {
dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
return NULL;
}
memset (serial, 0, sizeof(*serial));
serial->dev = usb_get_dev(dev);
serial->type = type;
serial->interface = interface;
serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct;
 
/* initialize the kobject portion of the usb_device */
kobject_init(&serial->kobj);
serial->kobj.ktype = &usb_serial_kobj_type;
 
return serial;
}
 
int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (interface);
struct usb_serial *serial = NULL;
struct usb_serial_port *port;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_device_type *type = NULL;
struct list_head *tmp;
int retval;
int found;
int minor;
int buffer_size;
int i;
int num_interrupt_in = 0;
int num_bulk_in = 0;
int num_bulk_out = 0;
int num_ports = 0;
int max_endpoints;
const struct usb_device_id *id_pattern = NULL;
 
/* loop through our list of known serial converters, and see if this
device matches. */
found = 0;
list_for_each (tmp, &usb_serial_driver_list) {
type = list_entry(tmp, struct usb_serial_device_type, driver_list);
id_pattern = usb_match_id(interface, type->id_table);
if (id_pattern != NULL) {
dbg("descriptor matches");
found = 1;
break;
}
}
if (!found) {
/* no match */
dbg("none matched");
return -ENODEV;
}
serial = create_serial (dev, interface, type);
if (!serial) {
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
return -ENODEV;
}
 
/* if this device type has a probe function, call it */
if (type->probe) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
retval = type->probe (serial, id_pattern);
module_put(type->owner);
 
if (retval) {
dbg ("sub driver rejected device");
kfree (serial);
return retval;
}
}
 
/* descriptor matches, let's find the endpoints needed */
/* check out the endpoints */
iface_desc = &interface->altsetting[0];
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */
dbg("found bulk in");
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
 
if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk out endpoint */
dbg("found bulk out");
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
}
 
#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
/* BEGIN HORRIBLE HACK FOR PL2303 */
/* this is needed due to the looney way its endpoints are set up */
if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
(dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
(dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
iface_desc = &dev->actconfig->interface[0]->altsetting[0];
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in for Prolific device on separate interface");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
}
}
 
/* Now make sure the PL-2303 is configured correctly.
* If not, give up now and hope this hack will work
* properly during a later invocation of usb_serial_probe
*/
if (num_bulk_in == 0 || num_bulk_out == 0) {
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree (serial);
return -ENODEV;
}
}
/* END HORRIBLE HACK FOR PL2303 */
#endif
 
/* found all that we need */
dev_info(&interface->dev, "%s converter detected\n", type->name);
 
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
if (num_ports == 0) {
dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
kfree (serial);
return -EIO;
}
}
#endif
if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */
if (type->calc_num_ports) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
kfree (serial);
return -EIO;
}
num_ports = type->calc_num_ports (serial);
module_put(type->owner);
}
if (!num_ports)
num_ports = type->num_ports;
}
 
if (get_free_serial (serial, num_ports, &minor) == NULL) {
dev_err(&interface->dev, "No more free serial devices\n");
kfree (serial);
return -ENOMEM;
}
 
serial->minor = minor;
serial->num_ports = num_ports;
serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in;
 
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in);
max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints;
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
for (i = 0; i < max_endpoints; ++i) {
port = kmalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
if (!port)
goto probe_error;
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
 
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
endpoint = bulk_in_endpoint[i];
port = serial->port[i];
port->read_urb = usb_alloc_urb (0, GFP_KERNEL);
if (!port->read_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
 
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_in_buffer) {
dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");
goto probe_error;
}
usb_fill_bulk_urb (port->read_urb, dev,
usb_rcvbulkpipe (dev,
endpoint->bEndpointAddress),
port->bulk_in_buffer, buffer_size,
serial->type->read_bulk_callback,
port);
}
 
for (i = 0; i < num_bulk_out; ++i) {
endpoint = bulk_out_endpoint[i];
port = serial->port[i];
port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->write_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->bulk_out_size = buffer_size;
port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->bulk_out_buffer) {
dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");
goto probe_error;
}
usb_fill_bulk_urb (port->write_urb, dev,
usb_sndbulkpipe (dev,
endpoint->bEndpointAddress),
port->bulk_out_buffer, buffer_size,
serial->type->write_bulk_callback,
port);
}
 
for (i = 0; i < num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i];
port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_in_urb) {
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
if (!port->interrupt_in_buffer) {
dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
goto probe_error;
}
usb_fill_int_urb (port->interrupt_in_urb, dev,
usb_rcvintpipe (dev,
endpoint->bEndpointAddress),
port->interrupt_in_buffer, buffer_size,
serial->type->read_int_callback, port,
endpoint->bInterval);
}
 
/* if this device type has an attach function, call it */
if (type->attach) {
if (!try_module_get(type->owner)) {
dev_err(&interface->dev, "module get failed, exiting\n");
goto probe_error;
}
retval = type->attach (serial);
module_put(type->owner);
if (retval < 0)
goto probe_error;
if (retval > 0) {
/* quietly accept this device, but don't bind to a serial port
* as it's about to disappear */
goto exit;
}
}
 
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
port->dev.parent = &interface->dev;
port->dev.driver = NULL;
port->dev.bus = &usb_serial_bus_type;
port->dev.release = &port_release;
 
snprintf26(&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
/*dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);*/
device_register (&port->dev);
}
 
usb_serial_console_init (debug, minor);
 
exit:
/* success */
usb_set_intfdata (interface, serial);
return 0;
 
probe_error:
for (i = 0; i < num_bulk_in; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->read_urb)
usb_free_urb (port->read_urb);
kfree(port->bulk_in_buffer);
}
for (i = 0; i < num_bulk_out; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->write_urb)
usb_free_urb (port->write_urb);
kfree(port->bulk_out_buffer);
}
for (i = 0; i < num_interrupt_in; ++i) {
port = serial->port[i];
if (!port)
continue;
if (port->interrupt_in_urb)
usb_free_urb (port->interrupt_in_urb);
kfree(port->interrupt_in_buffer);
}
 
/* return the minor range that this device had */
return_serial (serial);
 
/* free up any memory that we allocated */
for (i = 0; i < serial->num_port_pointers; ++i)
kfree(serial->port[i]);
kfree (serial);
return -EIO;
}
 
void usb_serial_disconnect(struct usb_interface *interface)
{
struct usb_serial *serial = usb_get_intfdata (interface);
struct device *dev = &interface->dev;
 
dbg ("%s", __FUNCTION__);
 
usb_set_intfdata (interface, NULL);
if (serial) {
/* let the last holder of this object
* cause it to be cleaned up */
kobject_put (&serial->kobj);
}
dev_info(dev, "device disconnected\n");
}
 
static struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
.write = serial_write,
.write_room = serial_write_room,
.ioctl = serial_ioctl,
.set_termios = serial_set_termios,
.throttle = serial_throttle,
.unthrottle = serial_unthrottle,
.break_ctl = serial_break,
.chars_in_buffer = serial_chars_in_buffer,
.read_proc = serial_read_proc,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
};
 
struct tty_driver *usb_serial_tty_driver;
 
/*static*/ int __init usb_serial_init(void)
{
int i;
int result = 0;
 
usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
if (!usb_serial_tty_driver)
return -ENOMEM;
 
/* Initialize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
 
bus_register(&usb_serial_bus_type);
 
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0) {
err("%s - registering generic driver failed", __FUNCTION__);
goto exit;
}
 
usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->devfs_name = "usb/tts/";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
usb_serial_tty_driver->minor_start = 0;
usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(usb_serial_tty_driver, &serial_ops);
result = tty_register_driver(usb_serial_tty_driver);
if (result) {
err("%s - tty_register_driver failed", __FUNCTION__);
goto exit_generic;
}
 
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if (result < 0) {
err("%s - usb_register failed", __FUNCTION__);
goto exit_tty;
}
 
info(DRIVER_DESC " " DRIVER_VERSION);
 
return result;
 
exit_tty:
tty_unregister_driver(usb_serial_tty_driver);
 
exit_generic:
usb_serial_generic_deregister();
 
exit:
err ("%s - returning with error %d", __FUNCTION__, result);
put_tty_driver(usb_serial_tty_driver);
return result;
}
 
 
/*static*/ void __exit usb_serial_exit(void)
{
usb_serial_console_exit();
 
usb_serial_generic_deregister();
 
usb_deregister(&usb_serial_driver);
tty_unregister_driver(usb_serial_tty_driver);
put_tty_driver(usb_serial_tty_driver);
bus_unregister(&usb_serial_bus_type);
}
 
 
module_init(usb_serial_init);
module_exit(usb_serial_exit);
 
#define set_to_generic_if_null(type, function) \
do { \
if (!type->function) { \
type->function = usb_serial_generic_##function; \
dbg("Had to override the " #function \
" usb serial operation with the generic one.");\
} \
} while (0)
 
static void fixup_generic(struct usb_serial_device_type *device)
{
set_to_generic_if_null(device, open);
set_to_generic_if_null(device, write);
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
}
 
int usb_serial_register(struct usb_serial_device_type *new_device)
{
int retval;
 
fixup_generic(new_device);
 
/* Add this device to our list of devices */
list_add(&new_device->driver_list, &usb_serial_driver_list);
 
retval = usb_serial_bus_register (new_device);
 
if (retval)
goto error;
 
info("USB Serial support registered for %s", new_device->name);
 
return retval;
error:
err("problem %d when registering driver %s", retval, new_device->name);
list_del(&new_device->driver_list);
 
return retval;
}
 
 
void usb_serial_deregister(struct usb_serial_device_type *device)
{
struct usb_serial *serial;
int i;
 
info("USB Serial deregistering driver %s", device->name);
 
/* clear out the serial_table if the device is attached to a port */
for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial = serial_table[i];
if ((serial != NULL) && (serial->type == device)) {
usb_driver_release_interface (&usb_serial_driver, serial->interface);
usb_serial_disconnect (serial->interface);
}
}
 
list_del(&device->driver_list);
usb_serial_bus_deregister (device);
}
 
 
 
/* If the usb-serial core is built into the core, the usb-serial drivers
need these symbols to load properly as modules. */
EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
EXPORT_SYMBOL(usb_serial_probe);
EXPORT_SYMBOL(usb_serial_disconnect);
EXPORT_SYMBOL(usb_serial_port_softint);
 
 
/* Module information */
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
 
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug enabled or not");
/shark/trunk/drivers/usb/serial/tty_io.c
1,210 → 1,319
/*
* linux/drivers/char/tty_io.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/kd.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
 
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
 
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/devfs_fs_kernel.h>
 
#include <linux/kmod.h>
 
#undef TTY_DEBUG_HANGUP
 
#define TTY_PARANOIA_CHECK 1
#define CHECK_TTY_COUNT 1
 
struct tty_ldisc ldiscs[NR_LDISCS];
 
struct termios tty_std_termios = { /* for the benefit of tty drivers */
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC
};
 
struct tty_driver *alloc_tty_driver(int lines)
{
struct tty_driver *driver;
 
driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
memset(driver, 0, sizeof(struct tty_driver));
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
}
return driver;
}
 
void put_tty_driver(struct tty_driver *driver)
{
kfree(driver);
}
 
void tty_set_operations(struct tty_driver *driver, struct tty_operations *op)
{
driver->open = op->open;
driver->close = op->close;
driver->write = op->write;
driver->put_char = op->put_char;
driver->flush_chars = op->flush_chars;
driver->write_room = op->write_room;
driver->chars_in_buffer = op->chars_in_buffer;
driver->ioctl = op->ioctl;
driver->set_termios = op->set_termios;
driver->throttle = op->throttle;
driver->unthrottle = op->unthrottle;
driver->stop = op->stop;
driver->start = op->start;
driver->hangup = op->hangup;
driver->break_ctl = op->break_ctl;
driver->flush_buffer = op->flush_buffer;
driver->set_ldisc = op->set_ldisc;
driver->wait_until_sent = op->wait_until_sent;
driver->send_xchar = op->send_xchar;
driver->read_proc = op->read_proc;
driver->write_proc = op->write_proc;
driver->tiocmget = op->tiocmget;
driver->tiocmset = op->tiocmset;
}
 
int tty_register_driver(struct tty_driver *driver)
{
return 0;
}
 
int tty_unregister_driver(struct tty_driver *driver)
{
return 0;
}
 
void tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
 
}
 
void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
 
}
 
void tty_flip_buffer_push(struct tty_struct *tty)
{
printk(KERN_INFO "%c\n", *(tty->flip.char_buf_ptr -1));
}
 
static void flush_to_ldisc(void *private_)
{
 
}
 
static struct tty_struct *alloc_tty_struct(void)
{
struct tty_struct *tty;
 
tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
// if (tty)
// memset(tty, 0, sizeof(struct tty_struct));
return tty;
}
 
void do_tty_hangup(void *data)
{
 
}
 
/*
* This subroutine initializes a tty structure.
*/
static void initialize_tty_struct(struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
tty->ldisc = ldiscs[N_TTY];
tty->pgrp = -1;
tty->flip.char_buf_ptr = tty->flip.char_buf;
tty->flip.flag_buf_ptr = tty->flip.flag_buf;
INIT_WORK(&tty->flip.work, flush_to_ldisc, tty);
init_MUTEX(&tty->flip.pty_sem);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
//*sema_init(&tty->atomic_read, 1);
//*sema_init(&tty->atomic_write, 1);
spin_lock_init(&tty->read_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, NULL, NULL);
}
 
extern int serial_open (struct tty_struct *tty, struct file * filp);
extern int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
 
struct tty_struct *tty;
int serial_usbport_open(int port_number)
{
int retval;
tty = alloc_tty_struct();
if(!tty)
goto fail_no_mem;
 
initialize_tty_struct (tty);
 
tty->termios = malloc (sizeof(struct termios));
*(tty->termios) = tty_std_termios;
 
retval = serial_open(tty, NULL);
return retval;
 
fail_no_mem:
return -ENOMEM;
}
 
int serial_usbport_write(const unsigned char *buf, int count)
{
int retval;
retval = serial_write(tty, 0, buf, count);
return retval;
 
// printk(KERN_DEBUG "######### retval=%d\n", retval);
}
/*
* linux/drivers/char/tty_io.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/kd.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
 
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/bitops.h>
 
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/devfs_fs_kernel.h>
 
#include <linux/kmod.h>
 
#undef TTY_DEBUG_HANGUP
 
#define TTY_PARANOIA_CHECK 1
#define CHECK_TTY_COUNT 1
 
struct tty_ldisc ldiscs[NR_LDISCS];
 
struct termios tty_std_termios = { /* for the benefit of tty drivers */
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B4800 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC
};
 
struct tty_driver *alloc_tty_driver(int lines)
{
struct tty_driver *driver;
 
driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
memset(driver, 0, sizeof(struct tty_driver));
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
}
return driver;
}
 
void put_tty_driver(struct tty_driver *driver)
{
kfree(driver);
}
 
void tty_set_operations(struct tty_driver *driver, struct tty_operations *op)
{
driver->open = op->open;
driver->close = op->close;
driver->write = op->write;
driver->put_char = op->put_char;
driver->flush_chars = op->flush_chars;
driver->write_room = op->write_room;
driver->chars_in_buffer = op->chars_in_buffer;
driver->ioctl = op->ioctl;
driver->set_termios = op->set_termios;
driver->throttle = op->throttle;
driver->unthrottle = op->unthrottle;
driver->stop = op->stop;
driver->start = op->start;
driver->hangup = op->hangup;
driver->break_ctl = op->break_ctl;
driver->flush_buffer = op->flush_buffer;
driver->set_ldisc = op->set_ldisc;
driver->wait_until_sent = op->wait_until_sent;
driver->send_xchar = op->send_xchar;
driver->read_proc = op->read_proc;
driver->write_proc = op->write_proc;
driver->tiocmget = op->tiocmget;
driver->tiocmset = op->tiocmset;
}
 
int tty_register_driver(struct tty_driver *driver)
{
return 0;
}
 
int tty_unregister_driver(struct tty_driver *driver)
{
return 0;
}
 
void tty_register_device(struct tty_driver *driver, unsigned index,
struct device *device)
{
 
}
 
void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
 
}
 
/*
* This routine is called out of the software interrupt to flush data
* from the flip buffer to the line discipline.
*/
static void flush_to_ldisc(void *private_)
{
struct tty_struct *tty = (struct tty_struct *) private_;
unsigned char *cp;
char *fp;
int count;
 
if (tty->flip.buf_num) {
cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
tty->flip.buf_num = 0;
tty->flip.char_buf_ptr = tty->flip.char_buf;
tty->flip.flag_buf_ptr = tty->flip.flag_buf;
} else {
cp = tty->flip.char_buf;
fp = tty->flip.flag_buf;
tty->flip.buf_num = 1;
tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
}
count = tty->flip.count;
tty->flip.count = 0;
 
tty->ldisc.receive_buf(tty, cp, fp, count);
}
 
 
void tty_flip_buffer_push(struct tty_struct *tty)
{
flush_to_ldisc((void *) tty);
}
 
static struct tty_struct *alloc_tty_struct(void)
{
struct tty_struct *tty;
 
tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
if (tty)
memset(tty, 0, sizeof(struct tty_struct));
return tty;
}
 
void do_tty_hangup(void *data)
{
 
}
 
/*
* This subroutine initializes a tty structure.
*/
static void initialize_tty_struct(struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
tty->magic = TTY_MAGIC;
tty->ldisc = ldiscs[N_TTY];
tty->pgrp = -1;
tty->flip.char_buf_ptr = tty->flip.char_buf;
tty->flip.flag_buf_ptr = tty->flip.flag_buf;
INIT_WORK(&tty->flip.work, flush_to_ldisc, tty);
init_MUTEX(&tty->flip.pty_sem);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
//*sema_init(&tty->atomic_read, 1);
//*sema_init(&tty->atomic_write, 1);
spin_lock_init(&tty->read_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, NULL, NULL);
}
 
extern int serial_open (struct tty_struct *tty, struct file * filp);
extern int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count);
 
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
const unsigned char *p;
char *f, flags = TTY_NORMAL;
int i;
char buf[64];
unsigned long cpuflags;
if (!tty->read_buf)
return;
 
spin_lock_irqsave(&tty->read_lock, cpuflags);
i = min(N_TTY_BUF_SIZE - tty->read_cnt, \
N_TTY_BUF_SIZE - tty->read_head);
i = min(count, i);
memcpy(tty->read_buf + tty->read_head, cp, i);
tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
tty->read_cnt += i;
spin_unlock_irqrestore(&tty->read_lock, cpuflags);
 
//** for (i=0; i<count; i++)
//** printk("%c", *(cp+i) );
}
 
/*
* Check whether to call the driver.unthrottle function.
* We test the TTY_THROTTLED bit first so that it always
* indicates the current state.
*/
static void check_unthrottle(struct tty_struct * tty)
{
if (tty->count &&
test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver->unthrottle)
tty->driver->unthrottle(tty);
}
 
/*
* Reset the read buffer counters, clear the flags,
* and make sure the driver is unthrottled. Called
* from n_tty_open() and n_tty_flush_buffer().
*/
static void reset_buffer_flags(struct tty_struct *tty)
{
unsigned long flags;
 
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_head = tty->read_tail = tty->read_cnt = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
check_unthrottle(tty);
}
 
int serial_usbport_open(void **private, int port_number)
{
int retval;
struct tty_struct *tty;
tty = alloc_tty_struct();
if(!tty)
goto fail_no_mem;
 
initialize_tty_struct (tty);
 
tty->termios = kmalloc (sizeof(struct termios), GFP_KERNEL);
*(tty->termios) = tty_std_termios;
tty->index = port_number;
tty->ldisc.receive_buf = n_tty_receive_buf;
if (!tty->read_buf) {
tty->read_buf = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->read_buf)
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
reset_buffer_flags(tty);
 
retval = serial_open(tty, NULL);
*private = (void*)tty;
return retval;
 
fail_no_mem:
return -ENOMEM;
}
 
int serial_usbport_write(void *private, const unsigned char *buf, int count)
{
int retval;
struct tty_struct *tty = (struct tty_struct*) private;
retval = serial_write(tty, 0, buf, count);
return retval;
}
 
int serial_usbport_read(void *private, char* data_in)
{
char c;
struct tty_struct *tty = (struct tty_struct*) private;
unsigned long flags;
 
if (tty->read_cnt)
{
c = tty->read_buf[tty->read_tail];
tty->read_tail = ((tty->read_tail+1) & \
(N_TTY_BUF_SIZE-1));
tty->read_cnt--;
*data_in = c;
return 1;
}
*data_in = 0;
return 0;
}
/shark/trunk/drivers/usb/serial/bus.c
1,142 → 1,145
/*
* USB Serial Converter Bus specific functions
*
* Copyright (C) 2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
 
static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_serial_device_type *driver;
const struct usb_serial_port *port;
 
/*
* drivers are already assigned to ports in serial_probe so it's
* a simple check here.
*/
port = to_usb_serial_port(dev);
if (!port)
return 0;
 
driver = to_usb_serial_driver(drv);
 
if (driver == port->serial->type)
return 1;
 
return 0;
}
 
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
};
 
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_device_type *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;
 
port = to_usb_serial_port(dev);
if (!port) {
retval = -ENODEV;
goto exit;
}
 
driver = port->serial->type;
if (driver->port_probe) {
if (!try_module_get(driver->owner)) {
dev_err(dev, "module get failed, exiting\n");
retval = -EIO;
goto exit;
}
retval = driver->port_probe (port);
module_put(driver->owner);
if (retval)
goto exit;
}
 
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n",
driver->name, minor, minor);
 
exit:
return retval;
}
 
static int usb_serial_device_remove (struct device *dev)
{
struct usb_serial_device_type *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;
 
port = to_usb_serial_port(dev);
if (!port) {
return -ENODEV;
}
 
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->owner)) {
dev_err(dev, "module get failed, exiting\n");
retval = -EIO;
goto exit;
}
retval = driver->port_remove (port);
module_put(driver->owner);
}
exit:
minor = port->number;
tty_unregister_device (usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->name, minor);
 
return retval;
}
 
int usb_serial_bus_register(struct usb_serial_device_type *device)
{
int retval;
 
if (device->short_name)
device->driver.name = (char *)device->short_name;
else
device->driver.name = (char *)device->name;
device->driver.bus = &usb_serial_bus_type;
device->driver.probe = usb_serial_device_probe;
device->driver.remove = usb_serial_device_remove;
 
retval = driver_register(&device->driver);
 
return retval;
}
 
void usb_serial_bus_deregister(struct usb_serial_device_type *device)
{
driver_unregister (&device->driver);
}
 
/*
* USB Serial Converter Bus specific functions
*
* Copyright (C) 2002 Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
 
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
static int debug;
#endif
 
#include "usb-serial.h"
 
static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_serial_device_type *driver;
const struct usb_serial_port *port;
 
/*
* drivers are already assigned to ports in serial_probe so it's
* a simple check here.
*/
port = to_usb_serial_port(dev);
if (!port)
return 0;
 
driver = to_usb_serial_driver(drv);
 
if (driver == port->serial->type)
return 1;
 
return 0;
}
 
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
};
 
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_device_type *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;
int i;
 
port = to_usb_serial_port(dev);
if (!port) {
retval = -ENODEV;
goto exit;
}
 
driver = port->serial->type;
if (driver->port_probe) {
if (!try_module_get(driver->owner)) {
dev_err(dev, "module get failed, exiting\n");
retval = -EIO;
goto exit;
}
retval = driver->port_probe (port);
module_put(driver->owner);
if (retval)
goto exit;
}
 
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n",
driver->name, minor, minor);
/* for (i=0; i<20; i++)
printk("ttyusb%d\n", minor);*/
 
exit:
return retval;
}
 
static int usb_serial_device_remove (struct device *dev)
{
struct usb_serial_device_type *driver;
struct usb_serial_port *port;
int retval = 0;
int minor;
 
port = to_usb_serial_port(dev);
if (!port) {
return -ENODEV;
}
 
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->owner)) {
dev_err(dev, "module get failed, exiting\n");
retval = -EIO;
goto exit;
}
retval = driver->port_remove (port);
module_put(driver->owner);
}
exit:
minor = port->number;
tty_unregister_device (usb_serial_tty_driver, minor);
dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
driver->name, minor);
 
return retval;
}
 
int usb_serial_bus_register(struct usb_serial_device_type *device)
{
int retval;
 
if (device->short_name)
device->driver.name = (char *)device->short_name;
else
device->driver.name = (char *)device->name;
device->driver.bus = &usb_serial_bus_type;
device->driver.probe = usb_serial_device_probe;
device->driver.remove = usb_serial_device_remove;
 
retval = driver_register(&device->driver);
 
return retval;
}
 
void usb_serial_bus_deregister(struct usb_serial_device_type *device)
{
driver_unregister (&device->driver);
}
 
/shark/trunk/drivers/usb/include/drivers/shark_usbserial26.h
0,0 → 1,18
#ifndef __SHARK_USBSERIAL26_H__
#define __SHARK_USBSERIAL26_H__
 
struct shark_tty_usbcom {
void *tty;
int port_number;
};
 
int shark_usb_serial_init(void);
void shark_usb_serial_close(void);
 
int
shark_usbcom_open(struct shark_tty_usbcom *tty_usb, int port_number);
 
char
shark_usbcom_read(struct shark_tty_usbcom *tty_usb);
 
#endif
/shark/trunk/drivers/usb/include/drivers/shark_pwc26.h
0,0 → 1,17
#ifndef __SHARK_PWC26_H__
#define __SHARK_PWC26_H__
 
struct PWC26_DEVICE
{
void* private_data;
int width;
int height;
BYTE* imgptr;
};
 
void shark_PWC_init();
int shark_PWC_read(struct PWC26_DEVICE *pwc26);
int shark_PWC_open(struct PWC26_DEVICE *pwc26, int width, int height, int fps, int quality, int webcamnr);
void shark_PWC_close(struct PWC26_DEVICE *pwc26);
 
#endif
/shark/trunk/drivers/usb/shark_glue/shark_usb.c
1,56 → 1,63
#include <kernel/kern.h>
 
extern int usb_init(void);
extern void usb_exit(void);
 
extern int ohci_hcd_pci_init (void);
extern void ohci_hcd_pci_cleanup (void);
 
extern int uhci_hcd_init(void);
extern void uhci_hcd_cleanup(void);
 
extern int usb_mouse_init(void);
extern void usb_mouse_exit(void);
 
extern int usb_kbd_init(void);
extern void usb_kbd_exit(void);
 
extern int hid_init(void);
extern void hid_exit(void);
 
 
static int usb_installed = FALSE;
 
/* to do: return error code */
int USB26_init()
{
if (usb_installed == TRUE)
return 0;
 
usb_init();
ohci_hcd_pci_init();
uhci_hcd_init();
usb_mouse_init();
usb_kbd_init();
hid_init();
usb_installed = TRUE;
 
return 0;
}
 
/* to do : add all usb closing functions ?*/
int USB26_close()
{
if (usb_installed == FALSE)
return -1;
ohci_hcd_pci_cleanup();
uhci_hcd_cleanup();
usb_mouse_exit();
usb_kbd_exit();
hid_exit();
usb_exit();
usb_installed = FALSE;
return 0;
}
#include <kernel/kern.h>
 
extern int usb_init(void);
extern void usb_exit(void);
 
extern int ohci_hcd_pci_init (void);
extern void ohci_hcd_pci_cleanup (void);
 
extern int uhci_hcd_init(void);
extern void uhci_hcd_cleanup(void);
 
extern int ehci_hcd_init(void);
extern void ehci_hcd_cleanup(void);
 
extern int usb_mouse_init(void);
extern void usb_mouse_exit(void);
 
extern int usb_kbd_init(void);
extern void usb_kbd_exit(void);
 
extern int hid_init(void);
extern void hid_exit(void);
 
 
static int usb_installed = FALSE;
 
/* to do: return error code */
int USB26_init()
{
if (usb_installed == TRUE)
return 0;
 
usb_init();
ehci_hcd_init();
ohci_hcd_pci_init();
uhci_hcd_init();
usb_mouse_init();
usb_kbd_init();
hid_init();
 
usb_installed = TRUE;
 
return 0;
}
 
/* to do : add all usb closing functions ?*/
int USB26_close()
{
if (usb_installed == FALSE)
return -1;
ehci_hcd_cleanup();
ohci_hcd_pci_cleanup();
uhci_hcd_cleanup();
usb_mouse_exit();
usb_kbd_exit();
hid_exit();
usb_exit();
 
usb_installed = FALSE;
 
return 0;
}
/shark/trunk/drivers/usb/shark_glue/shark_pwc.c
0,0 → 1,273
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/signal.h>
 
#include "media/pwc-ioctl.h"
#include <linux/videodev.h>
#include <drivers/shark_pwc26.h>
 
/*
* shark lowlevel wrapper
*/
 
struct PWC_data {
struct file* file;
struct pwc_imagesize RealSize;
struct pwc_coord m_ViewSize, m_RealSize;
struct pwc_coord m_Offset;
struct video_capability Capability;
struct pwc_probe Probe;
struct video_picture Picture;
struct video_window Window;
struct pwc_video_command VideoCmd;
void *m_pPWCXBuffer, *m_pInputBuffer, *m_pImageBuffer;
int m_Frames, len, m_UseRaw, m_ImageSize, m_ImageLen;
int m_Type, m_Bandlength, m_Bayer;
int m_InputLen;
};
 
 
extern int usb_pwc_init();
extern void* malloc(size_t size);
 
extern int pwc_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg);
extern int pwc_video_open(struct inode *inode, struct file *file);
extern int pwc_video_close(struct inode *inode, struct file *file);
extern ssize_t pwc_video_read(struct file *file, char *buf, size_t count, loff_t *ppos);
extern int pwc_video_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long arg);
 
void shark_PWC_init()
{
usb_pwc_init();
}
 
int shark_PWC_open(struct PWC26_DEVICE *pwc26, int width, int height, int fps, int quality, int webcamnr)
{
int err;
struct PWC_data *pwc_data;
struct file *file;
struct inode *inode;
 
pwc_data = malloc(sizeof(struct PWC_data));
pwc26->private_data = (void*)pwc_data;
 
if (!pwc_data)
return -ENOMEM;
 
memset(pwc_data, 0, sizeof(struct PWC_data));
file = malloc(sizeof(struct file));
if (!file)
return -ENOMEM;
 
file->f_dentry= malloc(sizeof(struct dentry));
if (!file->f_dentry)
return -ENOMEM;
 
file->f_dentry->d_inode = malloc(sizeof(struct inode));
if (!file->f_dentry->d_inode)
return -ENOMEM;
 
file->f_dentry->d_inode->i_rdev = webcamnr;
inode = file->f_dentry->d_inode;
 
pwc_data->file = file;
pwc_data->m_ViewSize.x = width;
pwc_data->m_ViewSize.y = height;
pwc_data->m_Frames = fps;
 
pwc_data->m_RealSize = pwc_data->m_ViewSize;
 
pwc_data->m_Offset.x = 0;
pwc_data->m_Offset.y = 0;
pwc_data->m_UseRaw = TRUE;
pwc_data->m_Bayer = FALSE;
pwc_data->m_pInputBuffer = NULL;
pwc_data->m_InputLen = 0;
pwc_data->m_pImageBuffer = NULL;
pwc_data->m_ImageLen = NULL;
pwc_data->m_Type = NULL;
 
pwc_data->m_pPWCXBuffer = malloc(60000); // large enoug for all cams
if (!pwc_data->m_pPWCXBuffer)
return -ENOMEM;
 
err=pwc_video_open(inode, file);
if (err <0)
return err;
 
pwc_video_do_ioctl(inode, file, VIDIOCGCAP, &pwc_data->Capability);
 
printk(KERN_INFO "Capability->type= %d\n", pwc_data->Capability.type);
printk(KERN_INFO "Capability->channels =%d\n",pwc_data->Capability.channels);
printk(KERN_INFO "Capability->audios=%d\n",pwc_data->Capability.audios);
printk(KERN_INFO "Capability->minwidth=%d\n",pwc_data->Capability.minwidth);
printk(KERN_INFO "Capability->minheight=%d\n",pwc_data->Capability.minheight);
printk(KERN_INFO "Capability->maxwidth=%d\n",pwc_data->Capability.maxwidth);
printk(KERN_INFO "Capability->maxheight=%d\n",pwc_data->Capability.maxheight);
 
memset(&pwc_data->Probe, 0, sizeof(pwc_data->Probe));
pwc_video_do_ioctl(inode, file, VIDIOCPWCPROBE, &pwc_data->Probe);
pwc_video_do_ioctl(inode, file, VIDIOCGPICT, &pwc_data->Picture);
 
if (pwc_data->m_UseRaw)
pwc_data->Picture.palette = VIDEO_PALETTE_RAW;
else
pwc_data->Picture.palette = VIDEO_PALETTE_YUV420P;
 
pwc_video_do_ioctl(inode, file, VIDIOCSPICT, &pwc_data->Picture);
pwc_video_do_ioctl(inode, file, VIDIOCGWIN, &pwc_data->Window);
 
/* unavailable in pwc 10.x */
if (pwc_data->m_Bayer)
{
// special raw Bayer mode
pwc_data->m_ViewSize.x = 640;
pwc_data->m_ViewSize.y = 480;
pwc_data->m_Frames = 5;
pwc_data->m_RealSize = pwc_data->m_ViewSize;
}
 
pwc_data->Window.width = pwc_data->m_ViewSize.x;
pwc_data->Window.height = pwc_data->m_ViewSize.y;
pwc_data->Window.flags = (pwc_data->m_Frames << PWC_FPS_SHIFT);
 
if (pwc_data->m_Bayer)
pwc_data->Window.flags |= PWC_FPS_SNAPSHOT;
 
pwc_video_do_ioctl(inode, file, VIDIOCSWIN, &pwc_data->Window);
 
if (pwc_data->m_UseRaw)
{
pwc_video_do_ioctl(inode, file, VIDIOCPWCGVIDCMD, &pwc_data->VideoCmd);
 
pwc_data->m_Type = pwc_data->VideoCmd.type;
pwc_data->m_InputLen = pwc_data->VideoCmd.frame_size;
pwc_data->m_Bandlength = pwc_data->VideoCmd.bandlength;
 
if (pwc_data->m_Bandlength > 0)
{
switch(pwc_data->m_Type)
{
case 645:
case 646:
pwcx_init_decompress_Nala(pwc_data->m_Type, pwc_data->VideoCmd.release, &pwc_data->VideoCmd.command_buf, pwc_data->m_pPWCXBuffer);
break;
 
case 675:
case 680:
case 690:
pwcx_init_decompress_Timon(pwc_data->m_Type, pwc_data->VideoCmd.release, &pwc_data->VideoCmd.command_buf, pwc_data->m_pPWCXBuffer);
break;
 
case 720:
case 730:
case 740:
case 750:
pwcx_init_decompress_Kiara(pwc_data->m_Type, pwc_data->VideoCmd.release, &pwc_data->VideoCmd.command_buf, pwc_data->m_pPWCXBuffer);
break;
 
default:
// qDebug("Unknown type of camera (%d)!", VideoCmd.type);
break;
} // ..switch
} // ..m_Bandlength > 0
 
if (pwc_video_do_ioctl(inode, file, VIDIOCPWCGREALSIZE, &pwc_data->RealSize) == 0)
{
pwc_data->m_Offset.x = (pwc_data->m_ViewSize.x - pwc_data->RealSize.width) / 2;
pwc_data->m_Offset.y = (pwc_data->m_ViewSize.y - pwc_data->RealSize.height) / 2;
}
}
 
pwc_data->m_ImageLen = pwc_data->m_ViewSize.x * pwc_data->m_ViewSize.y * 3;
pwc_data->m_pImageBuffer = malloc (pwc_data->m_ImageLen);
 
if (pwc_data->m_UseRaw)
{
pwc_data->m_pInputBuffer = malloc(pwc_data->m_InputLen);
}
else
{
if (pwc_data->m_pImageBuffer != 0)
{
pwc_data->m_pInputBuffer = pwc_data->m_pImageBuffer;
pwc_data->m_InputLen = pwc_data->m_ImageLen;
}
}
 
pwc26->width=pwc_data->m_ViewSize.x ;
pwc26->height=pwc_data->m_ViewSize.y ;
pwc26->imgptr=(BYTE*)pwc_data->m_pImageBuffer;
 
return 0;
}
 
int shark_PWC_read(struct PWC26_DEVICE *pwc26)
{
int len;
struct PWC_data *pwc_data = (struct PWC_data*)pwc26->private_data;
 
if (pwc_data->m_pInputBuffer == 0 || pwc_data->m_pImageBuffer == 0)
return -666;
 
len = pwc_video_read(pwc_data->file, pwc_data->m_pInputBuffer, pwc_data->m_InputLen, 0);
 
if (len > 0 && pwc_data->m_Bandlength > 0)
{
switch(pwc_data->m_Type)
{
case 645:
case 646:
pwcx_decompress_Nala(&pwc_data->m_RealSize, &pwc_data->m_ViewSize, &pwc_data->m_Offset, \
pwc_data->m_pInputBuffer, pwc_data->m_pImageBuffer, \
PWCX_FLAG_PLANAR, \
pwc_data->m_pPWCXBuffer, pwc_data->m_Bandlength);
break;
 
case 675:
case 680:
case 690:
pwcx_decompress_Timon(&pwc_data->m_RealSize, &pwc_data->m_ViewSize, &pwc_data->m_Offset, \
pwc_data->m_pInputBuffer, pwc_data->m_pImageBuffer, \
PWCX_FLAG_PLANAR, \
pwc_data->m_pPWCXBuffer, pwc_data->m_Bandlength);
break;
 
case 720:
case 730:
case 740:
case 750:
pwcx_decompress_Kiara(&pwc_data->m_RealSize, &pwc_data->m_ViewSize, &pwc_data->m_Offset, \
pwc_data->m_pInputBuffer, pwc_data->m_pImageBuffer, \
PWCX_FLAG_PLANAR | (pwc_data->m_Bayer ? PWCX_FLAG_BAYER : 0), \
pwc_data->m_pPWCXBuffer, pwc_data->m_Bandlength);
break;
}
}
return len;
}
 
void shark_PWC_close(struct PWC26_DEVICE *pwc26)
{
struct file *file;
struct inode *inode;
struct PWC_data *pwc_data = (struct PWC_data*)pwc26->private_data;
 
if (!pwc_data)
return;
 
free(pwc_data->m_pPWCXBuffer);
 
file = pwc_data->file;
inode = file->f_dentry->d_inode;
// pwc_video_close(inode, file);
 
free(inode);
free(file->f_dentry);
free(file);
free(pwc_data);
}
/shark/trunk/drivers/usb/shark_glue/shark_serial.c
0,0 → 1,56
#include <kernel/kern.h>
#include <drivers/shark_usbserial26.h>
 
extern int usb_serial_init();
extern void usb_serial_exit(void);
 
extern int pl2303_init();
extern void pl2303_exit();
 
extern int serial_usbport_open(void *tty, int port_number);
extern int serial_usbport_write(void *tty, const unsigned char *buf, int count);
extern int serial_usbport_read(void *private, char* data_in);
 
int shark_usb_serial_init()
{
usb_serial_init();
pl2303_init();
 
return 0;
}
 
void shark_usb_serial_close()
{
usb_serial_exit();
pl2303_exit();
}
 
int shark_usbcom_open(struct shark_tty_usbcom *tty_usb, int port_number)
{
int retval;
tty_usb->port_number = port_number;
 
retval = serial_usbport_open(&tty_usb->tty, tty_usb->port_number);
 
return retval;
}
 
int shark_usbcom_write(struct shark_tty_usbcom *tty_usb, const unsigned char *buf, int count)
{
int retval;
 
retval = serial_usbport_write(tty_usb->tty, buf, count);
 
return retval;
}
 
char shark_usbcom_read(struct shark_tty_usbcom *tty_usb)
{
int retval;
char data_in;
 
while ((retval = serial_usbport_read(tty_usb->tty, &data_in)) == 0);
 
return data_in;
/* do the hard stuff*/
}
/shark/trunk/drivers/usb/core/hcd.c
1168,6 → 1168,7
struct device *sys = 0;
unsigned long flags;
struct completion_splice splice;
struct list_head *tmp; /* 2.6.1 */
int retval;
 
if (!urb)
1206,10 → 1207,22
*/
WARN_ON (!HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_HALT);
 
/* insist the urb is still queued */
list_for_each(tmp, &dev->urb_list) {
if (tmp == &urb->urb_list)
break;
}
if (tmp != &urb->urb_list) {
retval = -EINVAL;
goto done;
}
 
/* removed for 2.6.1
if (!urb->hcpriv) {
retval = -EINVAL;
goto done;
}
*/
 
/* Any status except -EINPROGRESS means something already started to
* unlink this URB from the hardware. So there's no more work to do.
/shark/trunk/drivers/usb/core/buffer.c
1,139 → 1,139
/*
* DMA memory management for framework level HCD code (hc_driver)
*
* This implementation plugs in through generic "usb_bus" level methods,
* and works with real PCI, or when "pci device == null" makes sense.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
 
 
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
 
#include <linux/usb.h>
#include "hcd.h"
 
 
/*
* DMA-Coherent Buffers
*/
 
/* FIXME tune these based on pool statistics ... */
static const size_t pool_max [HCD_BUFFER_POOLS] = {
/* platforms without dma-friendly caches might need to
* prevent cacheline sharing...
*/
32,
128,
512,
PAGE_SIZE / 2
/* bigger --> allocate pages */
};
 
 
/* SETUP primitives */
 
/**
* hcd_buffer_create - initialize buffer pools
* @hcd: the bus whose buffer pools are to be initialized
* Context: !in_interrupt()
*
* Call this as part of initializing a host controller that uses the pci dma
* memory allocators. It initializes some pools of dma-consistent memory that
* will be shared by all drivers using that controller, or returns a negative
* errno value on error.
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
int hcd_buffer_create (struct usb_hcd *hcd)
{
char name [16];
int i, size;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
snprintf26(name, sizeof name, "buffer-%d", size);
hcd->pool [i] = pci_pool_create (name, hcd->pdev,
size, size, 0);
if (!hcd->pool [i]) {
hcd_buffer_destroy (hcd);
return -ENOMEM;
}
}
return 0;
}
EXPORT_SYMBOL (hcd_buffer_create);
 
 
/**
* hcd_buffer_destroy - deallocate buffer pools
* @hcd: the bus whose buffer pools are to be destroyed
* Context: !in_interrupt()
*
* This frees the buffer pools created by hcd_buffer_create().
*/
void hcd_buffer_destroy (struct usb_hcd *hcd)
{
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct pci_pool *pool = hcd->pool [i];
if (pool) {
pci_pool_destroy (pool);
hcd->pool [i] = 0;
}
}
}
EXPORT_SYMBOL (hcd_buffer_destroy);
 
 
/* sometimes alloc/free could use kmalloc with SLAB_DMA, for
* better sharing and to leverage mm/slab.c intelligence.
*/
 
void *hcd_buffer_alloc (
struct usb_bus *bus,
size_t size,
int mem_flags,
dma_addr_t *dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return pci_pool_alloc (hcd->pool [i], mem_flags, dma);
}
return pci_alloc_consistent (hcd->pdev, size, dma);
}
 
void hcd_buffer_free (
struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
pci_pool_free (hcd->pool [i], addr, dma);
return;
}
}
pci_free_consistent (hcd->pdev, size, addr, dma);
}
/*
* DMA memory management for framework level HCD code (hc_driver)
*
* This implementation plugs in through generic "usb_bus" level methods,
* and works with real PCI, or when "pci device == null" makes sense.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
 
 
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
 
#include <linux/usb.h>
#include "hcd.h"
 
 
/*
* DMA-Coherent Buffers
*/
 
/* FIXME tune these based on pool statistics ... */
static const size_t pool_max [HCD_BUFFER_POOLS] = {
/* platforms without dma-friendly caches might need to
* prevent cacheline sharing...
*/
32,
128,
512,
PAGE_SIZE / 2
/* bigger --> allocate pages */
};
 
 
/* SETUP primitives */
 
/**
* hcd_buffer_create - initialize buffer pools
* @hcd: the bus whose buffer pools are to be initialized
* Context: !in_interrupt()
*
* Call this as part of initializing a host controller that uses the pci dma
* memory allocators. It initializes some pools of dma-consistent memory that
* will be shared by all drivers using that controller, or returns a negative
* errno value on error.
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
int hcd_buffer_create (struct usb_hcd *hcd)
{
char name [16];
int i, size;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
snprintf26(name, sizeof name, "buffer-%d", size);
hcd->pool [i] = pci_pool_create (name, hcd->pdev,
size, size, 0);
if (!hcd->pool [i]) {
hcd_buffer_destroy (hcd);
return -ENOMEM;
}
}
return 0;
}
EXPORT_SYMBOL (hcd_buffer_create);
 
 
/**
* hcd_buffer_destroy - deallocate buffer pools
* @hcd: the bus whose buffer pools are to be destroyed
* Context: !in_interrupt()
*
* This frees the buffer pools created by hcd_buffer_create().
*/
void hcd_buffer_destroy (struct usb_hcd *hcd)
{
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct pci_pool *pool = hcd->pool [i];
if (pool) {
pci_pool_destroy (pool);
hcd->pool [i] = 0;
}
}
}
EXPORT_SYMBOL (hcd_buffer_destroy);
 
 
/* sometimes alloc/free could use kmalloc with SLAB_DMA, for
* better sharing and to leverage mm/slab.c intelligence.
*/
 
void *hcd_buffer_alloc (
struct usb_bus *bus,
size_t size,
int mem_flags,
dma_addr_t *dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return pci_pool_alloc_usb (hcd->pool [i], mem_flags, dma);
}
return pci_alloc_consistent_usb (hcd->pdev, size, dma);
}
 
void hcd_buffer_free (
struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
)
{
struct usb_hcd *hcd = bus->hcpriv;
int i;
 
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
pci_pool_free (hcd->pool [i], addr, dma);
return;
}
}
pci_free_consistent (hcd->pdev, size, addr, dma);
}
/shark/trunk/drivers/usb/core/hub.c
128,15 → 128,23
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_hub *hub = (struct usb_hub *)urb->context;
unsigned long flags;
//** unsigned long flags; 2.6.1
int status;
 
spin_lock(&hub_event_lock);
hub->urb_active = 0;
if (hub->urb_complete) { /* disconnect or rmmod */
complete(hub->urb_complete);
goto done;
}
 
switch (urb->status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
return;
 
goto done;
//** return; 2.6.1
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status);
153,12 → 161,12
hub->nerrors = 0;
 
/* Something happened, let khubd figure it out */
spin_lock_irqsave(&hub_event_lock, flags);
//** spin_lock_irqsave(&hub_event_lock, flags); 2.6.1
if (list_empty(&hub->event_list)) {
list_add(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
spin_unlock_irqrestore(&hub_event_lock, flags);
//** spin_unlock_irqrestore(&hub_event_lock, flags); 2.6.1
 
resubmit:
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
165,6 → 173,11
/* ENODEV means we raced disconnect() */
&& status != -ENODEV)
dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
if (status == 0)
hub->urb_active = 1;
done:
spin_unlock(&hub_event_lock);
}
 
/* USB 2.0 spec Section 11.24.2.3 */
469,6 → 482,7
message = "couldn't submit status urb";
goto fail;
}
hub->urb_active = 1;
/* Wake up khubd */
wake_up(&khubd_wait);
487,6 → 501,7
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
DECLARE_COMPLETION(urb_complete);
unsigned long flags;
 
if (!hub)
494,12 → 509,11
 
usb_set_intfdata (intf, NULL);
spin_lock_irqsave(&hub_event_lock, flags);
hub->urb_complete = &urb_complete;
 
/* Delete it and then reset it */
list_del(&hub->event_list);
INIT_LIST_HEAD(&hub->event_list);
list_del(&hub->hub_list);
INIT_LIST_HEAD(&hub->hub_list);
list_del_init(&hub->event_list);
list_del_init(&hub->hub_list);
 
spin_unlock_irqrestore(&hub_event_lock, flags);
 
512,6 → 526,8
 
if (hub->urb) {
usb_unlink_urb(hub->urb);
if (hub->urb_active)
wait_for_completion(&urb_complete);
usb_free_urb(hub->urb);
hub->urb = NULL;
}
1152,7 → 1168,6
// if (current->flags & PF_FREEZE)
// refrigerator(PF_IOTHREAD);
} while (!signal_pending(current));
printk(KERN_DEBUG "File: %s @hub_thread_exit\n", __FILE__);
 
dbg("hub_thread exiting");
complete_and_exit(&khubd_exited, 0);
/shark/trunk/drivers/usb/core/hub.h
172,6 → 172,8
struct usb_hub {
struct usb_interface *intf; /* the "real" device */
struct urb *urb; /* for interrupt polling pipe */
struct completion *urb_complete; /* wait for urb to end */
unsigned int urb_active:1;
 
/* buffer for urb ... 1 bit each for hub and children, rounded up */
char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
/shark/trunk/drivers/usb/core/message.c
26,7 → 26,6
 
static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
{
//printk(KERN_INFO "api\n");
complete((struct completion *)urb->context);
}
 
50,8 → 49,6
struct completion done;
struct timer_list timer;
int status;
struct pt_regs *regs;
 
init_completion(&done);
urb->context = &done;
318,15 → 315,6
int urb_flags;
int dma;
 
{
int i;
for (i=0; i<20; i++)
{
wait_ms26(300);
printk(KERN_INFO "usb_sg_init!!!!!!!\n");
}
}
 
if (!io || !dev || !sg
|| usb_pipecontrol (pipe)
|| usb_pipeisoc (pipe)
1115,7 → 1103,8
goto out;
 
dev->actconfig = cp;
if (!configuration)
//** if (!configuration) 2.6.1
if (!cp)
dev->state = USB_STATE_ADDRESS;
else {
dev->state = USB_STATE_CONFIGURED;
/shark/trunk/drivers/usb/core/usb.c
1,1547 → 1,1563
/*
* drivers/usb/usb.c
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
more docs, etc)
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
* generic USB things that the real drivers can use..
*
* Think of this as a "USB library" rather than anything else.
* It should be considered a slave, with no callbacks. Callbacks
* are evil.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
 
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
 
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
 
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
 
#include "hcd.h"
#include "usb.h"
 
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern int usb_major_init(void);
extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
 
 
int nousb; /* Disable USB when built into kernel image */
/* Not honored on modular build */
 
 
static int generic_probe (struct device *dev)
{
return 0;
}
static int generic_remove (struct device *dev)
{
return 0;
}
 
static struct device_driver usb_generic_driver = {
.name = "usb",
.bus = &usb_bus_type,
.probe = generic_probe,
.remove = generic_remove,
};
 
static int usb_generic_driver_data;
 
/* needs to be called with BKL held */
int usb_probe_interface(struct device *dev)
{
struct usb_interface * intf = to_usb_interface(dev);
struct usb_driver * driver = to_usb_driver(dev->driver);
const struct usb_device_id *id;
int error = -ENODEV;
 
dev_dbg(dev, "%s\n", __FUNCTION__);
 
if (!driver->probe)
return error;
 
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
down (&driver->serialize);
error = driver->probe (intf, id);
up (&driver->serialize);
}
if (!error)
intf->driver = driver;
 
return error;
}
 
int usb_unbind_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_driver *driver = to_usb_driver(dev->driver);
 
down(&driver->serialize);
 
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
 
if (intf->driver && intf->driver->disconnect)
intf->driver->disconnect(intf);
 
/* force a release and re-initialize the interface */
usb_driver_release_interface(driver, intf);
 
up(&driver->serialize);
 
return 0;
}
 
/**
* usb_register - register a USB driver
* @new_driver: USB operations for the driver
*
* Registers a USB driver with the USB core. The list of unattached
* interfaces will be rescanned whenever a new driver is added, allowing
* the new driver to attach to any recognized devices.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
int usb_register(struct usb_driver *new_driver)
{
int retval = 0;
 
if (nousb)
return -ENODEV;
 
new_driver->driver.name = (char *)new_driver->name;
new_driver->driver.bus = &usb_bus_type;
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
 
init_MUTEX(&new_driver->serialize);
 
retval = driver_register(&new_driver->driver);
 
if (!retval) {
info("registered new driver %s", new_driver->name);
usbfs_update_special();
} else {
err("problem %d when registering driver %s",
retval, new_driver->name);
}
 
return retval;
}
 
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
* Context: !in_interrupt (), must be called with BKL held
*
* Unlinks the specified driver from the internal USB driver list.
*
* NOTE: If you called usb_register_dev(), you still need to call
* usb_deregister_dev() to clean up your driver's allocated minor numbers,
* this * call will no longer do it for you.
*/
void usb_deregister(struct usb_driver *driver)
{
info("deregistering driver %s", driver->name);
 
driver_unregister (&driver->driver);
 
usbfs_update_special();
}
 
/**
* usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
* @dev: the device whose current configuration is considered
* @ifnum: the desired interface
*
* This walks the device descriptor for the currently active configuration
* and returns a pointer to the interface with that particular interface
* number, or null.
*
* Note that configuration descriptors are not required to assign interface
* numbers sequentially, so that it would be incorrect to assume that
* the first interface in that descriptor corresponds to interface zero.
* This routine helps device drivers avoid such mistakes.
* However, you should make sure that you do the right thing with any
* alternate settings available for this interfaces.
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
int i;
 
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
if (dev->actconfig->interface[i]->altsetting[0]
.desc.bInterfaceNumber == ifnum)
return dev->actconfig->interface[i];
 
return NULL;
}
 
/**
* usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
* @dev: the device whose current configuration+altsettings is considered
* @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
*
* This walks the device descriptor for the currently active configuration,
* and returns a pointer to the endpoint with that particular endpoint
* number, or null.
*
* Note that interface descriptors are not required to list endpoint
* numbers in any standardized order, so that it would be wrong to
* assume that ep2in precedes either ep5in, ep2out, or even ep1out.
* This routine helps device drivers avoid such mistakes.
*/
struct usb_endpoint_descriptor *
usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
{
int i, k;
 
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf;
struct usb_host_interface *alt;
 
/* only endpoints in current altseting are active */
intf = dev->actconfig->interface[i];
alt = intf->altsetting + intf->act_altsetting;
 
for (k = 0; k < alt->desc.bNumEndpoints; k++)
if (epnum == alt->endpoint[k].desc.bEndpointAddress)
return &alt->endpoint[k].desc;
}
 
return NULL;
}
 
/**
* usb_driver_claim_interface - bind a driver to an interface
* @driver: the driver to be bound
* @iface: the interface to which it will be bound
* @priv: driver data associated with that interface
*
* This is used by usb device drivers that need to claim more than one
* interface on a device when probing (audio and acm are current examples).
* No device driver should directly modify internal usb_interface or
* usb_device structure members.
*
* Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*/
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
if (!iface || !driver)
return -EINVAL;
 
/* this is mainly to lock against usbfs */
lock_kernel();
if (iface->driver) {
unlock_kernel();
err ("%s driver booted %s off interface %p",
driver->name, iface->driver->name, iface);
return -EBUSY;
} else {
dbg("%s driver claimed interface %p", driver->name, iface);
}
 
iface->driver = driver;
usb_set_intfdata(iface, priv);
unlock_kernel();
return 0;
}
 
/**
* usb_interface_claimed - returns true iff an interface is claimed
* @iface: the interface being checked
*
* This should be used by drivers to check other interfaces to see if
* they are available or not. If another driver has claimed the interface,
* they may not claim it. Otherwise it's OK to claim it using
* usb_driver_claim_interface().
*
* Returns true (nonzero) iff the interface is claimed, else false (zero).
*/
int usb_interface_claimed(struct usb_interface *iface)
{
if (!iface)
return 0;
 
return (iface->driver != NULL);
} /* usb_interface_claimed() */
 
/**
* usb_driver_release_interface - unbind a driver from an interface
* @driver: the driver to be unbound
* @iface: the interface from which it will be unbound
*
* In addition to unbinding the driver, this re-initializes the interface
* by selecting altsetting 0, the default alternate setting.
*
* This can be used by drivers to release an interface without waiting
* for their disconnect() methods to be called.
*
* When the USB subsystem disconnect()s a driver from some interface,
* it automatically invokes this method for that interface. That
* means that even drivers that used usb_driver_claim_interface()
* usually won't need to call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
/* this should never happen, don't release something that's not ours */
if (iface->driver && iface->driver != driver)
return;
 
usb_set_interface(interface_to_usbdev(iface),
iface->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(iface, NULL);
iface->driver = NULL;
}
 
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest
* @id: array of usb_device_id structures, terminated by zero entry
*
* usb_match_id searches an array of usb_device_id's and returns
* the first one matching the device or interface, or null.
* This is used when binding (or rebinding) a driver to an interface.
* Most USB device drivers will use this indirectly, through the usb core,
* but some layered driver frameworks use it directly.
* These device tables are exported with MODULE_DEVICE_TABLE, through
* modutils and "modules.usbmap", to support the driver loading
* functionality of USB hotplugging.
*
* What Matches:
*
* The "match_flags" element in a usb_device_id controls which
* members are used. If the corresponding bit is set, the
* value in the device_id must match its corresponding member
* in the device or interface descriptor, or else the device_id
* does not match.
*
* "driver_info" is normally used only by device drivers,
* but you can create a wildcard "matches anything" usb_device_id
* as a driver's "modules.usbmap" entry if you provide an id with
* only a nonzero "driver_info" field. If you do this, the USB device
* driver's probe() routine should use additional intelligence to
* decide whether to bind to the specified interface.
*
* What Makes Good usb_device_id Tables:
*
* The match algorithm is very simple, so that intelligence in
* driver selection must come from smart driver id records.
* Unless you have good reasons to use another selection policy,
* provide match elements only in related groups, and order match
* specifiers from specific to general. Use the macros provided
* for that purpose if you can.
*
* The most specific match specifiers use device descriptor
* data. These are commonly used with product-specific matches;
* the USB_DEVICE macro lets you provide vendor and product IDs,
* and you can also match against ranges of product revisions.
* These are widely used for devices with application or vendor
* specific bDeviceClass values.
*
* Matches based on device class/subclass/protocol specifications
* are slightly more general; use the USB_DEVICE_INFO macro, or
* its siblings. These are used with single-function devices
* where bDeviceClass doesn't specify that each interface has
* its own class.
*
* Matches based on interface class/subclass/protocol are the
* most general; they let drivers bind to any interface on a
* multiple-function device. Use the USB_INTERFACE_INFO
* macro, or its siblings, to match class-per-interface style
* devices (as recorded in bDeviceClass).
*
* Within those groups, remember that not all combinations are
* meaningful. For example, don't give a product version range
* without vendor and product IDs; or specify a protocol without
* its associated class and subclass.
*/
const struct usb_device_id *
usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
 
/* proc_connectinfo in devio.c may call us with id == NULL. */
if (id == NULL)
return NULL;
 
intf = &interface->altsetting [interface->act_altsetting];
dev = interface_to_usbdev(interface);
 
/* It is important to check that id->driver_info is nonzero,
since an entry that is all zeroes except for a nonzero
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
id->driver_info; id++) {
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != dev->descriptor.idVendor)
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != dev->descriptor.idProduct)
continue;
 
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > dev->descriptor.bcdDevice))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < dev->descriptor.bcdDevice))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
continue;
 
return id;
}
 
return NULL;
}
 
/**
* usb_find_interface - find usb_interface pointer for driver and device
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
* This walks the driver device list and returns a pointer to the interface
* with the matching minor. Note, this only works for devices that share the
* USB major number.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct list_head *entry;
struct device *dev;
struct usb_interface *intf;
 
list_for_each(entry, &drv->driver.devices) {
dev = container_of(entry, struct device, driver_list);
 
/* can't look at usb devices, only interfaces */
if (dev->driver == &usb_generic_driver)
continue;
 
intf = to_usb_interface(dev);
if (intf->minor == -1)
continue;
if (intf->minor == minor)
return intf;
}
 
/* no device found that matches */
return NULL;
}
 
static int usb_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
 
/* check for generic driver, which we don't match any device with */
if (drv == &usb_generic_driver)
return 0;
 
intf = to_usb_interface(dev);
 
usb_drv = to_usb_driver(drv);
id = usb_drv->id_table;
id = usb_match_id (intf, usb_drv->id_table);
if (id)
return 1;
 
return 0;
}
 
 
#ifdef CONFIG_HOTPLUG
 
/*
* USB hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when USB devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
 
dbg ("%s", __FUNCTION__);
 
if (!dev)
return -ENODEV;
 
/* Must check driver_data here, as on remove driver is always NULL */
if ((dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev (intf);
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
 
scratch = buffer;
 
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
*/
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif
 
/* per-device configurations are common */
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor,
usb_dev->descriptor.idProduct,
usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
/* class-based driver binding models */
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
 
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
envp [i++] = scratch;
length += snprintf (scratch, buffer_size - length,
"INTERFACE=%d/%d/%d",
intf->altsetting[alt].desc.bInterfaceClass,
intf->altsetting[alt].desc.bInterfaceSubClass,
intf->altsetting[alt].desc.bInterfaceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
}
envp [i++] = 0;
 
return 0;
}
 
#else
 
static int usb_hotplug (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
 
#endif /* CONFIG_HOTPLUG */
 
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this usb device are
* done.
*/
static void usb_release_dev(struct device *dev)
{
struct usb_device *udev;
 
udev = to_usb_device(dev);
 
if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
udev->bus->op->deallocate(udev);
usb_destroy_configuration(udev);
usb_bus_put(udev->bus);
kfree (udev);
}
 
/**
* usb_alloc_dev - allocate a usb device structure (usbcore-internal)
* @parent: hub to which device is connected
* @bus: bus used to access the device
* Context: !in_interrupt ()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
struct usb_device *dev;
 
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
 
memset(dev, 0, sizeof(*dev));
 
bus = usb_bus_get(bus);
if (!bus) {
kfree(dev);
return NULL;
}
 
device_initialize(&dev->dev);
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
 
if (!parent)
dev->devpath [0] = '0';
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
 
init_MUTEX(&dev->serialize);
 
if (dev->bus->op->allocate)
dev->bus->op->allocate(dev);
 
return dev;
}
 
/**
* usb_get_dev - increments the reference count of the usb device structure
* @dev: the device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for USB interfaces should normally record such references in
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_dev(), in their disconnect() methods.
*
* A pointer to the device with the incremented reference counter is returned.
*/
struct usb_device *usb_get_dev (struct usb_device *dev)
{
struct device *tmp;
 
if (!dev)
return NULL;
 
tmp = get_device(&dev->dev);
if (tmp)
return to_usb_device(tmp);
else
return NULL;
}
 
/**
* usb_put_dev - release a use of the usb device structure
* @dev: device that's been disconnected
*
* Must be called when a user of a device is finished with it. When the last
* user of the device calls this function, the memory of the device is freed.
*/
void usb_put_dev(struct usb_device *dev)
{
if (dev)
put_device(&dev->dev);
}
 
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
{
struct usb_device *ret_dev = NULL;
int child;
 
dbg("looking at vendor %d, product %d",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
 
/* see if this device matches */
if ((dev->descriptor.idVendor == vendor_id) &&
(dev->descriptor.idProduct == product_id)) {
dbg ("found the device!");
ret_dev = usb_get_dev(dev);
goto exit;
}
 
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
if (ret_dev)
goto exit;
}
}
exit:
return ret_dev;
}
 
/**
* usb_find_device - find a specific usb device in the system
* @vendor_id: the vendor id of the device to find
* @product_id: the product id of the device to find
*
* Returns a pointer to a struct usb_device if such a specified usb
* device is present in the system currently. The usage count of the
* device will be incremented if a device is found. Make sure to call
* usb_put_dev() when the caller is finished with the device.
*
* If a device with the specified vendor and product id is not found,
* NULL is returned.
*/
struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
{
struct list_head *buslist;
struct usb_bus *bus;
struct usb_device *dev = NULL;
down(&usb_bus_list_lock);
for (buslist = usb_bus_list.next;
buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of(buslist, struct usb_bus, bus_list);
dev = match_device(bus->root_hub, vendor_id, product_id);
if (dev)
goto exit;
}
exit:
up(&usb_bus_list_lock);
return dev;
}
 
/**
* usb_get_current_frame_number - return current bus frame number
* @dev: the device whose bus is being queried
*
* Returns the current frame number for the USB host controller
* used with the given USB device. This can be used when scheduling
* isochronous requests.
*
* Note that different kinds of host controller have different
* "scheduling horizons". While one type might support scheduling only
* 32 frames into the future, others could support scheduling up to
* 1024 frames into the future.
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
return dev->bus->op->get_frame_number (dev);
}
 
/*-------------------------------------------------------------------*/
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
*/
 
int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
{
struct usb_descriptor_header *header;
 
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
 
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
 
if (header->bDescriptorType == type) {
*ptr = header;
return 0;
}
 
buffer += header->bLength;
size -= header->bLength;
}
return -1;
}
 
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
* Context: !in_interrupt ()
*
* Something got disconnected. Get rid of it, and all of its children.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *dev = *pdev;
struct usb_bus *bus;
struct usb_operations *ops;
int i;
 
might_sleep ();
 
if (!dev) {
pr_debug ("%s nodev\n", __FUNCTION__);
return;
}
bus = dev->bus;
if (!bus) {
pr_debug ("%s nobus\n", __FUNCTION__);
return;
}
ops = bus->op;
 
*pdev = NULL;
 
/* mark the device as inactive, so any further urb submissions for
* this device will fail.
*/
dev->state = USB_STATE_NOTATTACHED;
down(&dev->serialize);
 
dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
 
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = dev->children + i;
if (*child)
usb_disconnect(child);
}
 
/* deallocate hcd/hardware state ... nuking all pending urbs and
* cleaning up all state associated with the current configuration
*/
usb_disable_device(dev, 0);
 
dev_dbg (&dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
usbfs_remove_device(dev);
}
up(&dev->serialize);
device_unregister(&dev->dev);
}
 
/**
* usb_choose_address - pick device address (usbcore-internal)
* @dev: newly detected device (in DEFAULT state)
*
* Picks a device address. It's up to the hub (or root hub) driver
* to handle and manage enumeration, starting from the DEFAULT state.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_choose_address(struct usb_device *dev)
{
int devnum;
// FIXME needs locking for SMP!!
/* why? this is called only from the hub thread,
* which hopefully doesn't run on multiple CPU's simultaneously 8-)
*/
 
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 
dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
 
if (devnum < 128) {
set_bit(devnum, dev->bus->devmap.devicemap);
dev->devnum = devnum;
}
}
 
 
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for usb_new_device()
int usb_set_address(struct usb_device *dev)
{
int retval;
 
if (dev->devnum == 0)
return -EINVAL;
if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
return -EINVAL;
retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0)
dev->state = USB_STATE_ADDRESS;
return retval;
}
 
/*
* By the time we get here, we chose a new device address
* and is in the default state. We need to identify the thing and
* get the ball rolling..
*
* Returns 0 for success, != 0 for error.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
#define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev, struct device *parent)
{
int err = -EINVAL;
int i;
int j;
 
/*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*
* Do it asap, so more driver model stuff (like the device.h message
* utilities) can be used in hcd submit/unlink code paths.
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
dev->dev.driver_data = &usb_generic_driver_data;
if (dev->dev.bus_id[0] == 0)
sprintf26 (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
 
/* dma masks come from the controller; readonly, except to hcd */
dev->dev.dma_mask = parent->dma_mask;
 
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
*/
switch (dev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, read the first 8
* bytes from the device descriptor to get bMaxPacketSize0;
* then correct our initial (small) guess.
*/
// FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
dev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i;
 
for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
err = usb_set_address(dev);
if (err >= 0)
break;
wait_ms(200);
}
if (err < 0) {
dev_err(&dev->dev,
"device not accepting address %d, error %d\n",
dev->devnum, err);
goto fail;
}
 
wait_ms(10); /* Let the SET_ADDRESS settle */
/* high and low speed devices don't need this... */
 
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err >= 8)
break;
wait_ms(100);
}
 
if (err < 8) {
dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
goto fail;
}
if (dev->speed == USB_SPEED_FULL) {
usb_disable_endpoint(dev, 0);
usb_endpoint_running(dev, 0, 1);
usb_endpoint_running(dev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
 
/* USB device state == addressed ... still not usable */
 
err = usb_get_device_descriptor(dev);
if (err < (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
goto fail;
}
 
err = usb_get_configuration(dev);
if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
 
/* Tell the world! */
dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
 
#ifdef DEBUG
if (dev->descriptor.iProduct)
usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
 
/* put device-specific files into sysfs */
err = device_add (&dev->dev);
if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err);
goto fail;
}
usb_create_driverfs_dev_files (dev);
 
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
*/
if (dev->descriptor.bNumConfigurations != 1) {
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
dev->config[0].desc.bConfigurationValue,
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev,
dev->config[0].desc.bConfigurationValue);
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n",
dev->config[0].desc.bConfigurationValue, err);
device_del(&dev->dev);
goto fail;
}
/* USB device state == configured ... usable */
 
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
 
return 0;
fail:
dev->state = USB_STATE_DEFAULT;
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return err;
}
 
/**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
* @dev: device the buffer will be used with
* @size: requested buffer size
* @mem_flags: affect whether allocation may block
* @dma: used to return DMA address of buffer
*
* Return value is either null (indicating no buffer could be allocated), or
* the cpu-space pointer to a buffer that may be used to perform DMA to the
* specified device. Such cpu-space buffers are returned along with the DMA
* address (through the pointer provided).
*
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
* to avoid behaviors like using "DMA bounce buffers", or tying down I/O
* mapping hardware for long idle periods. The implementation varies between
* platforms, depending on details of how DMA will work to this device.
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent.
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
void *usb_buffer_alloc (
struct usb_device *dev,
size_t size,
int mem_flags,
dma_addr_t *dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
return 0;
return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
}
 
/**
* usb_buffer_free - free memory allocated with usb_buffer_alloc()
* @dev: device the buffer was used with
* @size: requested buffer size
* @addr: CPU address of buffer
* @dma: DMA address of buffer
*
* This reclaims an I/O buffer, letting it be reused. The memory must have
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
void usb_buffer_free (
struct usb_device *dev,
size_t size,
void *addr,
dma_addr_t dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
return;
dev->bus->op->buffer_free (dev->bus, size, addr, dma);
}
 
/**
* usb_buffer_map - create DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer/setup_packet will be mapped
*
* Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are
* added to urb->transfer_flags if the operation succeeds. If the device
* is connected to this system through a non-DMA controller, this operation
* always succeeds.
*
* This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync()
* calls to synchronize memory and dma state.
*
* Reverse the effect of this call with usb_buffer_unmap().
*/
struct urb *usb_buffer_map (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return 0;
 
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single (controller,
urb->setup_packet,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
return urb;
}
 
/**
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
void usb_buffer_dmasync (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
 
if (controller->dma_mask) {
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_sync_single (controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
 
/**
* usb_buffer_unmap - free DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer will be unmapped
*
* Reverses the effect of usb_buffer_map().
*/
void usb_buffer_unmap (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
 
if (controller->dma_mask) {
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_unmap_single (controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
}
 
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
* Return value is either < 0 (indicating no buffers could be mapped), or
* the number of DMA mapping array entries in the scatterlist.
*
* The caller is responsible for placing the resulting DMA addresses from
* the scatterlist into URB transfer buffer pointers, and for setting the
* URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
*
* Top I/O rates come from queuing URBs, instead of waiting for each one
* to complete before starting the next I/O. This is particularly easy
* to do with scatterlists. Just allocate and submit one URB for each DMA
* mapping entry returned, stopping on the first error or when all succeed.
* Better yet, use the usb_sg_*() calls, which do that (and more) for you.
*
* This call would normally be used when translating scatterlist requests,
* rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
* may be able to coalesce mappings for improved I/O efficiency.
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
 
// FIXME generic api broken like pci, can't report errors
return dma_map_sg (controller, sg, nents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
 
dma_sync_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
 
dma_unmap_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
static int usb_device_suspend(struct device *dev, u32 state)
{
struct usb_interface *intf;
struct usb_driver *driver;
 
if ((dev->driver == NULL) ||
(dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
 
if (driver->suspend)
return driver->suspend(intf, state);
return 0;
}
 
static int usb_device_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
 
if ((dev->driver == NULL) ||
(dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
 
if (driver->resume)
return driver->resume(intf);
return 0;
}
 
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.hotplug = usb_hotplug,
.suspend = usb_device_suspend,
.resume = usb_device_resume,
};
 
#ifndef MODULE
 
static int __init usb_setup_disable(char *str)
{
nousb = 1;
return 1;
}
 
/* format to disable USB on kernel command line is: nousb */
__setup("nousb", usb_setup_disable);
 
#endif
 
/*
* for external read access to <nousb>
*/
int usb_disabled(void)
{
return nousb;
}
 
/*
* Init
*/
/*static*/ int __init usb_init(void)
{
if (nousb) {
info("USB support disabled\n");
return 0;
}
 
bus_register(&usb_bus_type);
usb_host_init();
usb_major_init();
usbfs_init();
usb_hub_init();
 
driver_register(&usb_generic_driver);
 
return 0;
}
 
/*
* Cleanup
*/
/*static*/ void __exit usb_exit(void)
{
/* This will matter if shutdown/reboot does exitcalls. */
if (nousb)
return;
 
driver_unregister(&usb_generic_driver);
// usb_major_cleanup();
// usbfs_cleanup();
// usb_hub_cleanup();
// usb_host_cleanup();
// bus_unregister(&usb_bus_type);
}
 
subsys_initcall(usb_init);
module_exit(usb_exit);
 
/*
* USB may be built into the kernel or be built as modules.
* These symbols are exported for device (or host controller)
* driver modules to use.
*/
EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_disabled);
 
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_put_dev);
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
 
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_disconnect);
 
EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
 
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
 
EXPORT_SYMBOL (usb_buffer_map);
EXPORT_SYMBOL (usb_buffer_dmasync);
EXPORT_SYMBOL (usb_buffer_unmap);
 
EXPORT_SYMBOL (usb_buffer_map_sg);
EXPORT_SYMBOL (usb_buffer_dmasync_sg);
EXPORT_SYMBOL (usb_buffer_unmap_sg);
 
MODULE_LICENSE("GPL");
/*
* drivers/usb/usb.c
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
* (C) Copyright Andreas Gal 1999
* (C) Copyright Gregory P. Smith 1999
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
* (C) Copyright Randy Dunlap 2000
* (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
more docs, etc)
* (C) Copyright Yggdrasil Computing, Inc. 2000
* (usb_device_id matching changes by Adam J. Richter)
* (C) Copyright Greg Kroah-Hartman 2002-2003
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
* generic USB things that the real drivers can use..
*
* Think of this as a "USB library" rather than anything else.
* It should be considered a slave, with no callbacks. Callbacks
* are evil.
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
 
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
 
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
 
#include <asm/io.h>
#include <asm/scatterlist.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
 
#include "hcd.h"
#include "usb.h"
 
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern int usb_major_init(void);
extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
 
 
int nousb; /* Disable USB when built into kernel image */
/* Not honored on modular build */
 
 
static int generic_probe (struct device *dev)
{
return 0;
}
static int generic_remove (struct device *dev)
{
return 0;
}
 
static struct device_driver usb_generic_driver = {
.name = "usb",
.bus = &usb_bus_type,
.probe = generic_probe,
.remove = generic_remove,
};
 
static int usb_generic_driver_data;
 
/* needs to be called with BKL held */
int usb_probe_interface(struct device *dev)
{
struct usb_interface * intf = to_usb_interface(dev);
struct usb_driver * driver = to_usb_driver(dev->driver);
const struct usb_device_id *id;
int error = -ENODEV;
 
dev_dbg(dev, "%s\n", __FUNCTION__);
 
if (!driver->probe)
return error;
 
/* driver claim() doesn't yet affect dev->driver... */
if (intf->driver)
return error;
 
id = usb_match_id (intf, driver->id_table);
if (id) {
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
error = driver->probe (intf, id);
}
if (!error)
intf->driver = driver;
 
return error;
}
 
int usb_unbind_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_driver *driver = intf->driver;
 
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
 
if (driver && driver->disconnect)
driver->disconnect(intf);
 
/* reset other interface state */
usb_set_interface(interface_to_usbdev(intf),
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
intf->driver = NULL;
 
return 0;
}
 
/**
* usb_register - register a USB driver
* @new_driver: USB operations for the driver
*
* Registers a USB driver with the USB core. The list of unattached
* interfaces will be rescanned whenever a new driver is added, allowing
* the new driver to attach to any recognized devices.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
* usb_register_dev() to enable that functionality. This function no longer
* takes care of that.
*/
int usb_register(struct usb_driver *new_driver)
{
int retval = 0;
 
if (nousb)
return -ENODEV;
 
new_driver->driver.name = (char *)new_driver->name;
new_driver->driver.bus = &usb_bus_type;
new_driver->driver.probe = usb_probe_interface;
new_driver->driver.remove = usb_unbind_interface;
 
init_MUTEX(&new_driver->serialize);
 
retval = driver_register(&new_driver->driver);
 
if (!retval) {
info("registered new driver %s", new_driver->name);
usbfs_update_special();
} else {
err("problem %d when registering driver %s",
retval, new_driver->name);
}
 
return retval;
}
 
/**
* usb_deregister - unregister a USB driver
* @driver: USB operations of the driver to unregister
* Context: !in_interrupt (), must be called with BKL held
*
* Unlinks the specified driver from the internal USB driver list.
*
* NOTE: If you called usb_register_dev(), you still need to call
* usb_deregister_dev() to clean up your driver's allocated minor numbers,
* this * call will no longer do it for you.
*/
void usb_deregister(struct usb_driver *driver)
{
info("deregistering driver %s", driver->name);
 
driver_unregister (&driver->driver);
 
usbfs_update_special();
}
 
/**
* usb_ifnum_to_if - get the interface object with a given interface number (usbcore-internal)
* @dev: the device whose current configuration is considered
* @ifnum: the desired interface
*
* This walks the device descriptor for the currently active configuration
* and returns a pointer to the interface with that particular interface
* number, or null.
*
* Note that configuration descriptors are not required to assign interface
* numbers sequentially, so that it would be incorrect to assume that
* the first interface in that descriptor corresponds to interface zero.
* This routine helps device drivers avoid such mistakes.
* However, you should make sure that you do the right thing with any
* alternate settings available for this interfaces.
*/
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
{
int i;
 
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
if (dev->actconfig->interface[i]->altsetting[0]
.desc.bInterfaceNumber == ifnum)
return dev->actconfig->interface[i];
 
return NULL;
}
 
/**
* usb_epnum_to_ep_desc - get the endpoint object with a given endpoint number
* @dev: the device whose current configuration+altsettings is considered
* @epnum: the desired endpoint, masked with USB_DIR_IN as appropriate.
*
* This walks the device descriptor for the currently active configuration,
* and returns a pointer to the endpoint with that particular endpoint
* number, or null.
*
* Note that interface descriptors are not required to list endpoint
* numbers in any standardized order, so that it would be wrong to
* assume that ep2in precedes either ep5in, ep2out, or even ep1out.
* This routine helps device drivers avoid such mistakes.
*/
struct usb_endpoint_descriptor *
usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
{
int i, k;
 
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *intf;
struct usb_host_interface *alt;
 
/* only endpoints in current altseting are active */
intf = dev->actconfig->interface[i];
alt = intf->altsetting + intf->act_altsetting;
 
for (k = 0; k < alt->desc.bNumEndpoints; k++)
if (epnum == alt->endpoint[k].desc.bEndpointAddress)
return &alt->endpoint[k].desc;
}
 
return NULL;
}
 
/**
* usb_driver_claim_interface - bind a driver to an interface
* @driver: the driver to be bound
* @iface: the interface to which it will be bound
* @priv: driver data associated with that interface
*
* This is used by usb device drivers that need to claim more than one
* interface on a device when probing (audio and acm are current examples).
* No device driver should directly modify internal usb_interface or
* usb_device structure members.
*
* Few drivers should need to use this routine, since the most natural
* way to bind to an interface is to return the private data from
* the driver's probe() method.
*/
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv)
{
if (!iface || !driver)
return -EINVAL;
 
if (iface->driver)
return -EBUSY;
 
/* FIXME should device_bind_driver() */
iface->driver = driver;
usb_set_intfdata(iface, priv);
return 0;
}
 
/**
* usb_interface_claimed - returns true iff an interface is claimed
* @iface: the interface being checked
*
* This should be used by drivers to check other interfaces to see if
* they are available or not. If another driver has claimed the interface,
* they may not claim it. Otherwise it's OK to claim it using
* usb_driver_claim_interface().
*
* Returns true (nonzero) iff the interface is claimed, else false (zero).
*/
int usb_interface_claimed(struct usb_interface *iface)
{
if (!iface)
return 0;
 
return (iface->driver != NULL);
} /* usb_interface_claimed() */
 
/**
* usb_driver_release_interface - unbind a driver from an interface
* @driver: the driver to be unbound
* @iface: the interface from which it will be unbound
*
* In addition to unbinding the driver, this re-initializes the interface
* by selecting altsetting 0, the default alternate setting.
*
* This can be used by drivers to release an interface without waiting
* for their disconnect() methods to be called.
*
* When the USB subsystem disconnect()s a driver from some interface,
* it automatically invokes this method for that interface. That
* means that even drivers that used usb_driver_claim_interface()
* usually won't need to call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
/* this should never happen, don't release something that's not ours */
if (!iface || !iface->driver || iface->driver != driver)
return;
 
if (iface->dev.driver) {
/* FIXME should be the ONLY case here */
device_release_driver(&iface->dev);
return;
}
 
usb_set_interface(interface_to_usbdev(iface),
iface->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(iface, NULL);
iface->driver = NULL;
}
 
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest
* @id: array of usb_device_id structures, terminated by zero entry
*
* usb_match_id searches an array of usb_device_id's and returns
* the first one matching the device or interface, or null.
* This is used when binding (or rebinding) a driver to an interface.
* Most USB device drivers will use this indirectly, through the usb core,
* but some layered driver frameworks use it directly.
* These device tables are exported with MODULE_DEVICE_TABLE, through
* modutils and "modules.usbmap", to support the driver loading
* functionality of USB hotplugging.
*
* What Matches:
*
* The "match_flags" element in a usb_device_id controls which
* members are used. If the corresponding bit is set, the
* value in the device_id must match its corresponding member
* in the device or interface descriptor, or else the device_id
* does not match.
*
* "driver_info" is normally used only by device drivers,
* but you can create a wildcard "matches anything" usb_device_id
* as a driver's "modules.usbmap" entry if you provide an id with
* only a nonzero "driver_info" field. If you do this, the USB device
* driver's probe() routine should use additional intelligence to
* decide whether to bind to the specified interface.
*
* What Makes Good usb_device_id Tables:
*
* The match algorithm is very simple, so that intelligence in
* driver selection must come from smart driver id records.
* Unless you have good reasons to use another selection policy,
* provide match elements only in related groups, and order match
* specifiers from specific to general. Use the macros provided
* for that purpose if you can.
*
* The most specific match specifiers use device descriptor
* data. These are commonly used with product-specific matches;
* the USB_DEVICE macro lets you provide vendor and product IDs,
* and you can also match against ranges of product revisions.
* These are widely used for devices with application or vendor
* specific bDeviceClass values.
*
* Matches based on device class/subclass/protocol specifications
* are slightly more general; use the USB_DEVICE_INFO macro, or
* its siblings. These are used with single-function devices
* where bDeviceClass doesn't specify that each interface has
* its own class.
*
* Matches based on interface class/subclass/protocol are the
* most general; they let drivers bind to any interface on a
* multiple-function device. Use the USB_INTERFACE_INFO
* macro, or its siblings, to match class-per-interface style
* devices (as recorded in bDeviceClass).
*
* Within those groups, remember that not all combinations are
* meaningful. For example, don't give a product version range
* without vendor and product IDs; or specify a protocol without
* its associated class and subclass.
*/
const struct usb_device_id *
usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
 
/* proc_connectinfo in devio.c may call us with id == NULL. */
if (id == NULL)
return NULL;
 
intf = &interface->altsetting [interface->act_altsetting];
dev = interface_to_usbdev(interface);
 
/* It is important to check that id->driver_info is nonzero,
since an entry that is all zeroes except for a nonzero
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
id->driver_info; id++) {
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != dev->descriptor.idVendor)
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != dev->descriptor.idProduct)
continue;
 
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > dev->descriptor.bcdDevice))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < dev->descriptor.bcdDevice))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
continue;
 
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
continue;
 
return id;
}
 
return NULL;
}
 
/**
* usb_find_interface - find usb_interface pointer for driver and device
* @drv: the driver whose current configuration is considered
* @minor: the minor number of the desired device
*
* This walks the driver device list and returns a pointer to the interface
* with the matching minor. Note, this only works for devices that share the
* USB major number.
*/
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct list_head *entry;
struct device *dev;
struct usb_interface *intf;
 
list_for_each(entry, &drv->driver.devices) {
dev = container_of(entry, struct device, driver_list);
 
/* can't look at usb devices, only interfaces */
if (dev->driver == &usb_generic_driver)
continue;
 
intf = to_usb_interface(dev);
if (intf->minor == -1)
continue;
if (intf->minor == minor)
return intf;
}
 
/* no device found that matches */
return NULL;
}
 
static int usb_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
 
/* check for generic driver, which we don't match any device with */
if (drv == &usb_generic_driver)
return 0;
 
intf = to_usb_interface(dev);
 
usb_drv = to_usb_driver(drv);
id = usb_drv->id_table;
id = usb_match_id (intf, usb_drv->id_table);
if (id)
return 1;
 
return 0;
}
 
 
#ifdef CONFIG_HOTPLUG
 
/*
* USB hotplugging invokes what /proc/sys/kernel/hotplug says
* (normally /sbin/hotplug) when USB devices get added or removed.
*
* This invokes a user mode policy agent, typically helping to load driver
* or other modules, configure the device, and more. Drivers can provide
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
*
* We're called either from khubd (the typical case) or from root hub
* (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
* delays in event delivery. Use sysfs (and DEVPATH) to make sure the
* device (and this configuration!) are still present.
*/
static int usb_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct usb_interface *intf;
struct usb_device *usb_dev;
char *scratch;
int i = 0;
int length = 0;
 
dbg ("%s", __FUNCTION__);
 
if (!dev)
return -ENODEV;
 
/* Must check driver_data here, as on remove driver is always NULL */
if ((dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev (intf);
if (usb_dev->devnum < 0) {
dbg ("device already deleted ??");
return -ENODEV;
}
if (!usb_dev->bus) {
dbg ("bus already removed?");
return -ENODEV;
}
 
scratch = buffer;
 
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
* even act as usermode drivers.
*
* FIXME reduce hardwired intelligence here
*/
envp [i++] = scratch;
length += snprintf26 (scratch, buffer_size - length,
"DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
#endif
 
/* per-device configurations are common */
envp [i++] = scratch;
length += snprintf26 (scratch, buffer_size - length, "PRODUCT=%x/%x/%x",
usb_dev->descriptor.idVendor,
usb_dev->descriptor.idProduct,
usb_dev->descriptor.bcdDevice);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
/* class-based driver binding models */
envp [i++] = scratch;
length += snprintf26 (scratch, buffer_size - length, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
if (usb_dev->descriptor.bDeviceClass == 0) {
int alt = intf->act_altsetting;
 
/* 2.4 only exposed interface zero. in 2.5, hotplug
* agents are called for all interfaces, and can use
* $DEVPATH/bInterfaceNumber if necessary.
*/
envp [i++] = scratch;
length += snprintf26 (scratch, buffer_size - length,
"INTERFACE=%d/%d/%d",
intf->altsetting[alt].desc.bInterfaceClass,
intf->altsetting[alt].desc.bInterfaceSubClass,
intf->altsetting[alt].desc.bInterfaceProtocol);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
 
}
envp [i++] = 0;
 
return 0;
}
 
#else
 
static int usb_hotplug (struct device *dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
 
#endif /* CONFIG_HOTPLUG */
 
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this usb device are
* done.
*/
static void usb_release_dev(struct device *dev)
{
struct usb_device *udev;
 
udev = to_usb_device(dev);
 
if (udev->bus && udev->bus->op && udev->bus->op->deallocate)
udev->bus->op->deallocate(udev);
usb_destroy_configuration(udev);
usb_bus_put(udev->bus);
kfree (udev);
}
 
/**
* usb_alloc_dev - allocate a usb device structure (usbcore-internal)
* @parent: hub to which device is connected
* @bus: bus used to access the device
* Context: !in_interrupt ()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
struct usb_device *dev;
 
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
 
memset(dev, 0, sizeof(*dev));
 
bus = usb_bus_get(bus);
if (!bus) {
kfree(dev);
return NULL;
}
 
device_initialize(&dev->dev);
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
 
if (!parent)
dev->devpath [0] = '0';
dev->bus = bus;
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
 
init_MUTEX(&dev->serialize);
 
if (dev->bus->op->allocate)
dev->bus->op->allocate(dev);
 
return dev;
}
 
/**
* usb_get_dev - increments the reference count of the usb device structure
* @dev: the device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for USB interfaces should normally record such references in
* their probe() methods, when they bind to an interface, and release
* them by calling usb_put_dev(), in their disconnect() methods.
*
* A pointer to the device with the incremented reference counter is returned.
*/
struct usb_device *usb_get_dev (struct usb_device *dev)
{
struct device *tmp;
 
if (!dev)
return NULL;
 
tmp = get_device(&dev->dev);
if (tmp)
return to_usb_device(tmp);
else
return NULL;
}
 
/**
* usb_put_dev - release a use of the usb device structure
* @dev: device that's been disconnected
*
* Must be called when a user of a device is finished with it. When the last
* user of the device calls this function, the memory of the device is freed.
*/
void usb_put_dev(struct usb_device *dev)
{
if (dev)
put_device(&dev->dev);
}
 
static struct usb_device *match_device(struct usb_device *dev,
u16 vendor_id, u16 product_id)
{
struct usb_device *ret_dev = NULL;
int child;
 
dbg("looking at vendor %d, product %d",
dev->descriptor.idVendor,
dev->descriptor.idProduct);
 
/* see if this device matches */
if ((dev->descriptor.idVendor == vendor_id) &&
(dev->descriptor.idProduct == product_id)) {
dbg ("found the device!");
ret_dev = usb_get_dev(dev);
goto exit;
}
 
/* look through all of the children of this device */
for (child = 0; child < dev->maxchild; ++child) {
if (dev->children[child]) {
ret_dev = match_device(dev->children[child],
vendor_id, product_id);
if (ret_dev)
goto exit;
}
}
exit:
return ret_dev;
}
 
/**
* usb_find_device - find a specific usb device in the system
* @vendor_id: the vendor id of the device to find
* @product_id: the product id of the device to find
*
* Returns a pointer to a struct usb_device if such a specified usb
* device is present in the system currently. The usage count of the
* device will be incremented if a device is found. Make sure to call
* usb_put_dev() when the caller is finished with the device.
*
* If a device with the specified vendor and product id is not found,
* NULL is returned.
*/
struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
{
struct list_head *buslist;
struct usb_bus *bus;
struct usb_device *dev = NULL;
down(&usb_bus_list_lock);
for (buslist = usb_bus_list.next;
buslist != &usb_bus_list;
buslist = buslist->next) {
bus = container_of(buslist, struct usb_bus, bus_list);
dev = match_device(bus->root_hub, vendor_id, product_id);
if (dev)
goto exit;
}
exit:
up(&usb_bus_list_lock);
return dev;
}
 
/**
* usb_get_current_frame_number - return current bus frame number
* @dev: the device whose bus is being queried
*
* Returns the current frame number for the USB host controller
* used with the given USB device. This can be used when scheduling
* isochronous requests.
*
* Note that different kinds of host controller have different
* "scheduling horizons". While one type might support scheduling only
* 32 frames into the future, others could support scheduling up to
* 1024 frames into the future.
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
return dev->bus->op->get_frame_number (dev);
}
 
/*-------------------------------------------------------------------*/
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
*/
 
int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
{
struct usb_descriptor_header *header;
 
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
 
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
 
if (header->bDescriptorType == type) {
*ptr = header;
return 0;
}
 
buffer += header->bLength;
size -= header->bLength;
}
return -1;
}
 
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
* Context: !in_interrupt ()
*
* Something got disconnected. Get rid of it, and all of its children.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *dev = *pdev;
struct usb_bus *bus;
struct usb_operations *ops;
int i;
 
might_sleep ();
 
if (!dev) {
pr_debug ("%s nodev\n", __FUNCTION__);
return;
}
bus = dev->bus;
if (!bus) {
pr_debug ("%s nobus\n", __FUNCTION__);
return;
}
ops = bus->op;
 
*pdev = NULL;
 
/* mark the device as inactive, so any further urb submissions for
* this device will fail.
*/
dev->state = USB_STATE_NOTATTACHED;
down(&dev->serialize);
 
dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
 
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = dev->children + i;
if (*child)
usb_disconnect(child);
}
 
/* deallocate hcd/hardware state ... nuking all pending urbs and
* cleaning up all state associated with the current configuration
*/
usb_disable_device(dev, 0);
 
dev_dbg (&dev->dev, "unregistering device\n");
/* Free the device number and remove the /proc/bus/usb entry */
if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
usbfs_remove_device(dev);
}
up(&dev->serialize);
device_unregister(&dev->dev);
}
 
/**
* usb_choose_address - pick device address (usbcore-internal)
* @dev: newly detected device (in DEFAULT state)
*
* Picks a device address. It's up to the hub (or root hub) driver
* to handle and manage enumeration, starting from the DEFAULT state.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_choose_address(struct usb_device *dev)
{
int devnum;
// FIXME needs locking for SMP!!
/* why? this is called only from the hub thread,
* which hopefully doesn't run on multiple CPU's simultaneously 8-)
*/
 
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
 
dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
 
if (devnum < 128) {
set_bit(devnum, dev->bus->devmap.devicemap);
dev->devnum = devnum;
}
}
 
 
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for usb_new_device()
int usb_set_address(struct usb_device *dev)
{
int retval;
 
if (dev->devnum == 0)
return -EINVAL;
if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
return -EINVAL;
retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0)
dev->state = USB_STATE_ADDRESS;
return retval;
}
 
/*
* By the time we get here, we chose a new device address
* and is in the default state. We need to identify the thing and
* get the ball rolling..
*
* Returns 0 for success, != 0 for error.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
#define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev, struct device *parent)
{
int err = -EINVAL;
int i;
int j;
int config;
 
 
/*
* Set the driver for the usb device to point to the "generic" driver.
* This prevents the main usb device from being sent to the usb bus
* probe function. Yes, it's a hack, but a nice one :)
*
* Do it asap, so more driver model stuff (like the device.h message
* utilities) can be used in hcd submit/unlink code paths.
*/
usb_generic_driver.bus = &usb_bus_type;
dev->dev.parent = parent;
dev->dev.driver = &usb_generic_driver;
dev->dev.bus = &usb_bus_type;
dev->dev.driver_data = &usb_generic_driver_data;
if (dev->dev.bus_id[0] == 0)
sprintf26 (&dev->dev.bus_id[0], "%d-%s",
dev->bus->busnum, dev->devpath);
 
/* dma masks come from the controller; readonly, except to hcd */
dev->dev.dma_mask = parent->dma_mask;
 
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
*/
switch (dev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, read the first 8
* bytes from the device descriptor to get bMaxPacketSize0;
* then correct our initial (small) guess.
*/
// FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
dev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i;
 
for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
err = usb_set_address(dev);
if (err >= 0)
break;
wait_ms(200);
}
if (err < 0) {
dev_err(&dev->dev,
"device not accepting address %d, error %d\n",
dev->devnum, err);
goto fail;
}
 
wait_ms(10); /* Let the SET_ADDRESS settle */
/* high and low speed devices don't need this... */
 
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
if (err >= 8)
break;
wait_ms(100);
}
 
if (err < 8) {
dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
goto fail;
}
if (dev->speed == USB_SPEED_FULL) {
usb_disable_endpoint(dev, 0);
usb_endpoint_running(dev, 0, 1);
usb_endpoint_running(dev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
 
/* USB device state == addressed ... still not usable */
 
err = usb_get_device_descriptor(dev);
if (err < (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
goto fail;
}
 
err = usb_get_configuration(dev);
if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
 
/* Tell the world! */
dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
 
#ifdef DEBUG
if (dev->descriptor.iProduct)
usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
 
/* put device-specific files into sysfs */
err = device_add (&dev->dev);
if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err);
goto fail;
}
usb_create_driverfs_dev_files (dev);
 
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
* NOTE: should interact with hub power budgeting.
*/
config = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
if (dev->config[i].interface[0]->altsetting
->desc.bInterfaceClass
== USB_CLASS_VENDOR_SPEC)
continue;
config = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
config,
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev, config);
 
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n",
config, err);
device_del(&dev->dev);
goto fail;
}
 
/* USB device state == configured ... usable */
 
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
 
return 0;
fail:
dev->state = USB_STATE_DEFAULT;
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
return err;
}
 
/**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
* @dev: device the buffer will be used with
* @size: requested buffer size
* @mem_flags: affect whether allocation may block
* @dma: used to return DMA address of buffer
*
* Return value is either null (indicating no buffer could be allocated), or
* the cpu-space pointer to a buffer that may be used to perform DMA to the
* specified device. Such cpu-space buffers are returned along with the DMA
* address (through the pointer provided).
*
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
* to avoid behaviors like using "DMA bounce buffers", or tying down I/O
* mapping hardware for long idle periods. The implementation varies between
* platforms, depending on details of how DMA will work to this device.
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent.
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
void *usb_buffer_alloc (
struct usb_device *dev,
size_t size,
int mem_flags,
dma_addr_t *dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
return 0;
return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
}
 
/**
* usb_buffer_free - free memory allocated with usb_buffer_alloc()
* @dev: device the buffer was used with
* @size: requested buffer size
* @addr: CPU address of buffer
* @dma: DMA address of buffer
*
* This reclaims an I/O buffer, letting it be reused. The memory must have
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
void usb_buffer_free (
struct usb_device *dev,
size_t size,
void *addr,
dma_addr_t dma
)
{
if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
return;
dev->bus->op->buffer_free (dev->bus, size, addr, dma);
}
 
/**
* usb_buffer_map - create DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer/setup_packet will be mapped
*
* Return value is either null (indicating no buffer could be mapped), or
* the parameter. URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP are
* added to urb->transfer_flags if the operation succeeds. If the device
* is connected to this system through a non-DMA controller, this operation
* always succeeds.
*
* This call would normally be used for an urb which is reused, perhaps
* as the target of a large periodic transfer, with usb_buffer_dmasync()
* calls to synchronize memory and dma state.
*
* Reverse the effect of this call with usb_buffer_unmap().
*/
struct urb *usb_buffer_map (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return 0;
 
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single (controller,
urb->setup_packet,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
} else
urb->transfer_dma = ~0;
urb->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
return urb;
}
 
/**
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
void usb_buffer_dmasync (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
 
if (controller->dma_mask) {
dma_sync_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_sync_single (controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
 
/**
* usb_buffer_unmap - free DMA mapping(s) for an urb
* @urb: urb whose transfer_buffer will be unmapped
*
* Reverses the effect of usb_buffer_map().
*/
void usb_buffer_unmap (struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
 
if (!urb
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|| !urb->dev
|| !(bus = urb->dev->bus)
|| !(controller = bus->controller))
return;
 
if (controller->dma_mask) {
dma_unmap_single (controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_unmap_single (controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
| URB_NO_SETUP_DMA_MAP);
}
 
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
* Return value is either < 0 (indicating no buffers could be mapped), or
* the number of DMA mapping array entries in the scatterlist.
*
* The caller is responsible for placing the resulting DMA addresses from
* the scatterlist into URB transfer buffer pointers, and for setting the
* URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
*
* Top I/O rates come from queuing URBs, instead of waiting for each one
* to complete before starting the next I/O. This is particularly easy
* to do with scatterlists. Just allocate and submit one URB for each DMA
* mapping entry returned, stopping on the first error or when all succeed.
* Better yet, use the usb_sg_*() calls, which do that (and more) for you.
*
* This call would normally be used when translating scatterlist requests,
* rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
* may be able to coalesce mappings for improved I/O efficiency.
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| usb_pipecontrol (pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
 
// FIXME generic api broken like pci, can't report errors
return dma_map_sg (controller, sg, nents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
 
dma_sync_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
 
if (!dev
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return;
 
dma_unmap_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
 
static int usb_device_suspend(struct device *dev, u32 state)
{
struct usb_interface *intf;
struct usb_driver *driver;
 
if ((dev->driver == NULL) ||
(dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
 
if (driver->suspend)
return driver->suspend(intf, state);
return 0;
}
 
static int usb_device_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
 
if ((dev->driver == NULL) ||
(dev->driver == &usb_generic_driver) ||
(dev->driver_data == &usb_generic_driver_data))
return 0;
 
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);
 
if (driver->resume)
return driver->resume(intf);
return 0;
}
 
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.hotplug = usb_hotplug,
.suspend = usb_device_suspend,
.resume = usb_device_resume,
};
 
#ifndef MODULE
 
static int __init usb_setup_disable(char *str)
{
nousb = 1;
return 1;
}
 
/* format to disable USB on kernel command line is: nousb */
__setup("nousb", usb_setup_disable);
 
#endif
 
/*
* for external read access to <nousb>
*/
int usb_disabled(void)
{
return nousb;
}
 
/*
* Init
*/
/*static*/ int __init usb_init(void)
{
if (nousb) {
info("USB support disabled\n");
return 0;
}
 
bus_register(&usb_bus_type);
usb_host_init();
usb_major_init();
usbfs_init();
usb_hub_init();
 
driver_register(&usb_generic_driver);
 
return 0;
}
 
/*
* Cleanup
*/
/*static*/ void __exit usb_exit(void)
{
/* This will matter if shutdown/reboot does exitcalls. */
if (nousb)
return;
 
driver_unregister(&usb_generic_driver);
// usb_major_cleanup();
// usbfs_cleanup();
// usb_hub_cleanup();
// usb_host_cleanup();
// bus_unregister(&usb_bus_type);
}
 
subsys_initcall(usb_init);
module_exit(usb_exit);
 
/*
* USB may be built into the kernel or be built as modules.
* These symbols are exported for device (or host controller)
* driver modules to use.
*/
EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_disabled);
 
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_put_dev);
EXPORT_SYMBOL(usb_get_dev);
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
 
EXPORT_SYMBOL(usb_reset_device);
EXPORT_SYMBOL(usb_disconnect);
 
EXPORT_SYMBOL(__usb_get_extra_descriptor);
 
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
 
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
 
EXPORT_SYMBOL (usb_buffer_map);
EXPORT_SYMBOL (usb_buffer_dmasync);
EXPORT_SYMBOL (usb_buffer_unmap);
 
EXPORT_SYMBOL (usb_buffer_map_sg);
EXPORT_SYMBOL (usb_buffer_dmasync_sg);
EXPORT_SYMBOL (usb_buffer_unmap_sg);
 
MODULE_LICENSE("GPL");
/shark/trunk/drivers/usb/host/ohci-mem.c
1,147 → 1,147
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
*/
 
/*-------------------------------------------------------------------------*/
 
/*
* There's basically three types of memory:
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use pci_pool or pci_alloc_consistent
* - driver buffers, read/written by HC ... the hcd glue or the
* device driver provides us with dma addresses
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pagable.
*/
 
/*-------------------------------------------------------------------------*/
 
static struct usb_hcd *ohci_hcd_alloc (void)
{
struct ohci_hcd *ohci;
 
ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);
if (ohci != 0) {
memset (ohci, 0, sizeof (struct ohci_hcd));
ohci->hcd.product_desc = "OHCI Host Controller";
return &ohci->hcd;
}
return 0;
}
 
static void ohci_hcd_free (struct usb_hcd *hcd)
{
kfree (hcd_to_ohci (hcd));
}
 
/*-------------------------------------------------------------------------*/
 
static int ohci_mem_init (struct ohci_hcd *ohci)
{
ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
sizeof (struct td),
32 /* byte alignment */,
0 /* no page-crossing issues */);
if (!ohci->td_cache)
return -ENOMEM;
ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
sizeof (struct ed),
16 /* byte alignment */,
0 /* no page-crossing issues */);
if (!ohci->ed_cache) {
pci_pool_destroy (ohci->td_cache);
return -ENOMEM;
}
return 0;
}
 
static void ohci_mem_cleanup (struct ohci_hcd *ohci)
{
if (ohci->td_cache) {
pci_pool_destroy (ohci->td_cache);
ohci->td_cache = 0;
}
if (ohci->ed_cache) {
pci_pool_destroy (ohci->ed_cache);
ohci->ed_cache = 0;
}
}
 
/*-------------------------------------------------------------------------*/
 
/* ohci "done list" processing needs this mapping */
static inline struct td *
dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
{
struct td *td;
 
td_dma &= TD_MASK;
td = hc->td_hash [TD_HASH_FUNC(td_dma)];
while (td && td->td_dma != td_dma)
td = td->td_hash;
return td;
}
 
/* TDs ... */
static struct td *
td_alloc (struct ohci_hcd *hc, int mem_flags)
{
dma_addr_t dma;
struct td *td;
 
td = pci_pool_alloc (hc->td_cache, mem_flags, &dma);
if (td) {
/* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma;
/* hashed in td_fill */
}
return td;
}
 
static void
td_free (struct ohci_hcd *hc, struct td *td)
{
struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
 
while (*prev && *prev != td)
prev = &(*prev)->td_hash;
if (*prev)
*prev = td->td_hash;
else if ((td->hwINFO & TD_DONE) != 0)
ohci_dbg (hc, "no hash for td %p\n", td);
pci_pool_free (hc->td_cache, td, td->td_dma);
}
 
/*-------------------------------------------------------------------------*/
 
/* EDs ... */
static struct ed *
ed_alloc (struct ohci_hcd *hc, int mem_flags)
{
dma_addr_t dma;
struct ed *ed;
 
ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
if (ed) {
memset (ed, 0, sizeof (*ed));
INIT_LIST_HEAD (&ed->td_list);
ed->dma = dma;
}
return ed;
}
 
static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
pci_pool_free (hc->ed_cache, ed, ed->dma);
}
 
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
*/
 
/*-------------------------------------------------------------------------*/
 
/*
* There's basically three types of memory:
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use pci_pool or pci_alloc_consistent_usb
* - driver buffers, read/written by HC ... the hcd glue or the
* device driver provides us with dma addresses
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pagable.
*/
 
/*-------------------------------------------------------------------------*/
 
static struct usb_hcd *ohci_hcd_alloc (void)
{
struct ohci_hcd *ohci;
 
ohci = (struct ohci_hcd *) kmalloc (sizeof *ohci, GFP_KERNEL);
if (ohci != 0) {
memset (ohci, 0, sizeof (struct ohci_hcd));
ohci->hcd.product_desc = "OHCI Host Controller";
return &ohci->hcd;
}
return 0;
}
 
static void ohci_hcd_free (struct usb_hcd *hcd)
{
kfree (hcd_to_ohci (hcd));
}
 
/*-------------------------------------------------------------------------*/
 
static int ohci_mem_init (struct ohci_hcd *ohci)
{
ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev,
sizeof (struct td),
32 /* byte alignment */,
0 /* no page-crossing issues */);
if (!ohci->td_cache)
return -ENOMEM;
ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
sizeof (struct ed),
16 /* byte alignment */,
0 /* no page-crossing issues */);
if (!ohci->ed_cache) {
pci_pool_destroy (ohci->td_cache);
return -ENOMEM;
}
return 0;
}
 
static void ohci_mem_cleanup (struct ohci_hcd *ohci)
{
if (ohci->td_cache) {
pci_pool_destroy (ohci->td_cache);
ohci->td_cache = 0;
}
if (ohci->ed_cache) {
pci_pool_destroy (ohci->ed_cache);
ohci->ed_cache = 0;
}
}
 
/*-------------------------------------------------------------------------*/
 
/* ohci "done list" processing needs this mapping */
static inline struct td *
dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
{
struct td *td;
 
td_dma &= TD_MASK;
td = hc->td_hash [TD_HASH_FUNC(td_dma)];
while (td && td->td_dma != td_dma)
td = td->td_hash;
return td;
}
 
/* TDs ... */
static struct td *
td_alloc (struct ohci_hcd *hc, int mem_flags)
{
dma_addr_t dma;
struct td *td;
 
td = pci_pool_alloc_usb (hc->td_cache, mem_flags, &dma);
if (td) {
/* in case hc fetches it, make it look dead */
memset (td, 0, sizeof *td);
td->hwNextTD = cpu_to_le32 (dma);
td->td_dma = dma;
/* hashed in td_fill */
}
return td;
}
 
static void
td_free (struct ohci_hcd *hc, struct td *td)
{
struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
 
while (*prev && *prev != td)
prev = &(*prev)->td_hash;
if (*prev)
*prev = td->td_hash;
else if ((td->hwINFO & TD_DONE) != 0)
ohci_dbg (hc, "no hash for td %p\n", td);
pci_pool_free (hc->td_cache, td, td->td_dma);
}
 
/*-------------------------------------------------------------------------*/
 
/* EDs ... */
static struct ed *
ed_alloc (struct ohci_hcd *hc, int mem_flags)
{
dma_addr_t dma;
struct ed *ed;
 
ed = pci_pool_alloc_usb (hc->ed_cache, mem_flags, &dma);
if (ed) {
memset (ed, 0, sizeof (*ed));
INIT_LIST_HEAD (&ed->td_list);
ed->dma = dma;
}
return ed;
}
 
static void
ed_free (struct ohci_hcd *hc, struct ed *ed)
{
pci_pool_free (hc->ed_cache, ed, ed->dma);
}
 
/shark/trunk/drivers/usb/host/ehci-hcd.c
121,8 → 121,10
 
/* Initial IRQ latency: lower than default */
static int log2_irq_thresh = 0; // 0 to 6
module_param (log2_irq_thresh, int, S_IRUGO);
 
/*module_param (log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
*/
 
#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
483,7 → 485,7
* involved with the root hub.
*/
ehci->reboot_notifier.notifier_call = ehci_reboot;
register_reboot_notifier (&ehci->reboot_notifier);
// register_reboot_notifier (&ehci->reboot_notifier);
 
ehci->hcd.state = USB_STATE_RUNNING;
writel (FLAG_CF, &ehci->regs->configured_flag);
540,7 → 542,7
 
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
unregister_reboot_notifier (&ehci->reboot_notifier);
// unregister_reboot_notifier (&ehci->reboot_notifier);
 
remove_debug_files (ehci);
 
1011,7 → 1013,7
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_LICENSE ("GPL");
 
static int __init init (void)
/*static*/ int __init ehci_hcd_init (void)
{
if (usb_disabled())
return -ENODEV;
1023,10 → 1025,10
 
return pci_module_init (&ehci_pci_driver);
}
module_init (init);
//module_init (init);
 
static void __exit cleanup (void)
/*static*/ void __exit ehci_hcd_cleanup (void)
{
pci_unregister_driver (&ehci_pci_driver);
}
module_exit (cleanup);
//module_exit (cleanup);
/shark/trunk/drivers/usb/host/ehci.h
134,7 → 134,7
t = EHCI_SHRINK_JIFFIES;
break;
}
t += jiffies;
t += jiffies26;
// all timings except IAA watchdog can be overridden.
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
/shark/trunk/drivers/usb/host/ohci-hcd.c
1,691 → 1,691
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
* [ (C) Copyright 1999 Linus Torvalds ]
* [ (C) Copyright 1999 Gregory P. Smith]
*
*
* OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
* interfaces (though some non-x86 Intel chips use it). It supports
* smarter hardware than UHCI. A download link for the spec available
* through the http://www.usb.org website.
*
* History:
*
* 2003/02/24 show registers in sysfs (Kevin Brosius)
*
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
* bandwidth accounting; if debugging, show schedules in driverfs
* 2002/07/19 fixes to management of ED and schedule state.
* 2002/06/09 SA-1111 support (Christopher Hoover)
* 2002/06/01 remember frame when HC won't see EDs any more; use that info
* to fix urb unlink races caused by interrupt latency assumptions;
* minor ED field and function naming updates
* 2002/01/18 package as a patch for 2.5.3; this should match the
* 2.4.17 kernel modulo some bugs being fixed.
*
* 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
* from post-2.4.5 patches.
* 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
* 2001/09/07 match PCI PM changes, errnos from Linus' tree
* 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
* pbook pci quirks gone (please fix pbook pci sw!) (db)
*
* 2001/04/08 Identify version on module load (gb)
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
pci_map_single (db)
* 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
* 2001/03/07 hcca allocation uses pci_alloc_consistent (Steve Longerbeam)
*
* 2000/09/26 fixed races in removing the private portion of the urb
* 2000/09/07 disable bulk and control lists when unlinking the last
* endpoint descriptor in order to avoid unrecoverable errors on
* the Lucent chips. (rwc@sgi)
* 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
* urb unlink probs, indentation fixes
* 2000/08/11 various oops fixes mostly affecting iso and cleanup from
* device unplugs.
* 2000/06/28 use PCI hotplug framework, for better power management
* and for Cardbus support (David Brownell)
* 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
* when the controller loses power; handle UE; cleanup; ...
*
* v5.2 1999/12/07 URB 3rd preview,
* v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
* v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
* i386: HUB, Keyboard, Mouse, Printer
*
* v4.3 1999/10/27 multiple HCs, bulk_request
* v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
* v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
* v4.0 1999/08/18
* v3.0 1999/06/25
* v2.1 1999/05/09 code clean up
* v2.0 1999/05/04
* v1.0 1999/04/27 initial release
*
* This file is licenced under the GPL.
*/
#include <linuxcomp.h>
 
#include <linux/config.h>
 
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#else
# undef DEBUG
#endif
 
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h>
#include "../core/hcd.h"
 
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
 
 
#define DRIVER_VERSION "2003 Oct 13"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
/*-------------------------------------------------------------------------*/
 
//#define OHCI_VERBOSE_DEBUG /* not always helpful */
 
/* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT \
(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
 
#define OHCI_UNLINK_TIMEOUT (HZ / 10)
 
/*-------------------------------------------------------------------------*/
 
static const char hcd_name [] = "ohci_hcd";
 
#include "ohci.h"
 
static inline void disable (struct ohci_hcd *ohci)
{
ohci->hcd.state = USB_STATE_HALT;
}
 
#include "ohci-hub.c"
#include "ohci-dbg.c"
#include "ohci-mem.c"
#include "ohci-q.c"
 
/*-------------------------------------------------------------------------*/
 
/*
* queue up an urb for anything except the root hub
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
struct urb *urb,
int mem_flags
) {
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ed *ed;
urb_priv_t *urb_priv;
unsigned int pipe = urb->pipe;
int i, size = 0;
unsigned long flags;
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))
return -ENOMEM;
 
/* for the private part of the URB we need the number of TDs (size) */
switch (ed->type) {
case PIPE_CONTROL:
/* td_submit_urb() doesn't yet handle these */
if (urb->transfer_buffer_length > 4096)
return -EMSGSIZE;
 
/* 1 TD for setup, 1 for ACK, plus ... */
size = 2;
/* FALLTHROUGH */
// case PIPE_INTERRUPT:
// case PIPE_BULK:
default:
/* one TD for every 4096 Bytes (can be upto 8K) */
size += urb->transfer_buffer_length / 4096;
/* ... and for any remaining bytes ... */
if ((urb->transfer_buffer_length % 4096) != 0)
size++;
/* ... and maybe a zero length packet to wrap it up */
if (size == 0)
size++;
else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
&& (urb->transfer_buffer_length
% usb_maxpacket (urb->dev, pipe,
usb_pipeout (pipe))) == 0)
size++;
break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets;
break;
}
 
/* allocate the private part of the URB */
urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
mem_flags);
if (!urb_priv)
return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
/* fill the private part of the URB */
urb_priv->length = size;
urb_priv->ed = ed;
 
/* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) {
urb_priv->td [i] = td_alloc (ohci, mem_flags);
if (!urb_priv->td [i]) {
urb_priv->length = i;
urb_free_priv (ohci, urb_priv);
return -ENOMEM;
}
}
 
spin_lock_irqsave (&ohci->lock, flags);
 
/* don't submit to a dead HC */
if (!HCD_IS_RUNNING(ohci->hcd.state)) {
retval = -ENODEV;
goto fail;
}
 
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
if (retval < 0)
goto fail;
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = le16_to_cpu (ohci->hcca->frame_no);
 
/* delay a few frames before the first TD */
frame += max_t (u16, 8, ed->interval);
frame &= ~(ed->interval - 1);
frame |= ed->branch;
urb->start_frame = frame;
 
/* yes, only URB_ISO_ASAP is supported, and
* urb->start_frame is never used as input.
*/
}
} else if (ed->type == PIPE_ISOCHRONOUS)
urb->start_frame = ed->last_iso + ed->interval;
 
/* fill the TDs and link them to the ed; and
* enable that part of the schedule, if needed
* and update count of queued periodic urbs
*/
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
 
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&ohci->lock, flags);
return retval;
}
 
/*
* decouple the URB from the HC queues (TDs, urb_priv); it's
* already marked using urb->status. reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
#endif
 
spin_lock_irqsave (&ohci->lock, flags);
if (HCD_IS_RUNNING(ohci->hcd.state)) {
urb_priv_t *urb_priv;
 
/* Unless an IRQ completed the unlink while it was being
* handed to us, flag it for unlink and giveback, and force
* some upcoming INTR_SF to call finish_unlinks()
*/
urb_priv = urb->hcpriv;
if (urb_priv) {
if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed);
}
} else {
/*
* with HC dead, we won't respect hc queue pointers
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv) {
spin_unlock (&ohci->lock);
finish_urb (ohci, urb, NULL);
spin_lock (&ohci->lock);
}
}
spin_unlock_irqrestore (&ohci->lock, flags);
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
/* frees config/altsetting state for endpoints,
* including ED memory, dummy TD, and bulk/intr data toggle
*/
 
static void
ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int epnum = ep & USB_ENDPOINT_NUMBER_MASK;
unsigned long flags;
struct ed *ed;
unsigned limit = 1000;
 
/* ASSERT: any requests/urbs are being unlinked */
/* ASSERT: nobody can be submitting urbs for this any more */
 
epnum <<= 1;
if (epnum != 0 && !(ep & USB_DIR_IN))
epnum |= 1;
 
rescan:
spin_lock_irqsave (&ohci->lock, flags);
ed = dev->ep [epnum];
if (!ed)
goto done;
 
if (!HCD_IS_RUNNING (ohci->hcd.state))
ed->state = ED_IDLE;
switch (ed->state) {
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
WARN_ON (limit-- == 0);
spin_unlock_irqrestore (&ohci->lock, flags);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (1);
goto rescan;
case ED_IDLE: /* fully unlinked */
if (list_empty (&ed->td_list)) {
td_free (ohci, ed->dummy);
ed_free (ohci, ed);
break;
}
/* else FALL THROUGH */
default:
/* caller was supposed to have unlinked any requests;
* that's not our job. can't recover; must leak ed.
*/
ohci_err (ohci, "leak ed %p (#%d) state %d%s\n",
ed, epnum, ed->state,
list_empty (&ed->td_list) ? "" : " (has tds)");
td_free (ohci, ed->dummy);
break;
}
dev->ep [epnum] = 0;
done:
spin_unlock_irqrestore (&ohci->lock, flags);
return;
}
 
static int ohci_get_frame (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
return le16_to_cpu (ohci->hcca->frame_no);
}
 
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
 
/* reset the HC and BUS */
 
static int hc_reset (struct ohci_hcd *ohci)
{
u32 temp;
 
/* SMM owns the HC? not for long!
* On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
*/
#ifndef __hppa__
if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
 
/* this timeout is arbitrary. we make it long, so systems
* depending on usb keyboards may be usable even if the
* BIOS/SMM code seems pretty broken.
*/
temp = 500; /* arbitrary: five seconds */
 
writel (OHCI_INTR_OC, &ohci->regs->intrenable);
writel (OHCI_OCR, &ohci->regs->cmdstatus);
while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
if (--temp == 0) {
ohci_err (ohci, "USB HC TakeOver failed!\n");
return -1;
}
}
}
#endif
 
/* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
ohci_dbg (ohci, "reset, control = 0x%x\n",
readl (&ohci->regs->control));
 
/* Reset USB (needed by some controllers); RemoteWakeupConnected
* saved if boot firmware (BIOS/SMM/...) told us it's connected
*/
ohci->hc_control = readl (&ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
writel (ohci->hc_control, &ohci->regs->control);
// flush those pci writes
(void) readl (&ohci->regs->control);
wait_ms (50);
 
/* HC Reset requires max 10 us delay */
writel (OHCI_HCR, &ohci->regs->cmdstatus);
temp = 30; /* ... allow extra time */
while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--temp == 0) {
ohci_err (ohci, "USB HC reset timed out!\n");
return -1;
}
udelay (1);
}
 
/* now we're in the SUSPEND state ... must go OPERATIONAL
* within 2msec else HC enters RESUME
*
* ... but some hardware won't init fmInterval "by the book"
* (SiS, OPTi ...), so reset again instead. SiS doesn't need
* this if we write fmInterval after we're OPERATIONAL.
*/
writel (ohci->hc_control, &ohci->regs->control);
// flush those pci writes
(void) readl (&ohci->regs->control);
 
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
#define FI 0x2edf /* 12000 bits per frame (-1) */
#define LSTHRESH 0x628 /* lowspeed bit threshold */
 
/* Start an OHCI controller, set the BUS operational
* enable interrupts
* connect the virtual root hub
*/
static int hc_start (struct ohci_hcd *ohci)
{
u32 mask, tmp;
struct usb_device *udev;
struct usb_bus *bus;
 
spin_lock_init (&ohci->lock);
disable (ohci);
 
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
writel (0, &ohci->regs->ed_controlhead);
writel (0, &ohci->regs->ed_bulkhead);
 
/* a reset clears this */
writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
 
/* force default fmInterval (we won't adjust it); init thresholds
* for last FS and LS packets, reserve 90% for periodic.
*/
writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval);
writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);
writel (LSTHRESH, &ohci->regs->lsthresh);
 
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
*/
if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
|| !readl (&ohci->regs->periodicstart)) {
ohci_err (ohci, "init err\n");
return -EOVERFLOW;
}
 
/* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
writel (ohci->hc_control, &ohci->regs->control);
ohci->hcd.state = USB_STATE_RUNNING;
 
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable);
 
/* handle root hub init quirks ... */
tmp = roothub_a (ohci);
tmp &= ~(RH_A_PSM | RH_A_OCPM);
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
/* NSC 87560 and maybe others */
tmp |= RH_A_NOCP;
tmp &= ~(RH_A_POTPGT | RH_A_NPS);
} else {
/* hub power always on; required for AMD-756 and some
* Mac platforms, use this mode everywhere by default
*/
tmp |= RH_A_NPS;
}
writel (tmp, &ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status);
writel (0, &ohci->regs->roothub.b);
// flush those pci writes
(void) readl (&ohci->regs->control);
 
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
/* connect the virtual root hub */
bus = hcd_to_bus (&ohci->hcd);
bus->root_hub = udev = usb_alloc_dev (NULL, bus);
ohci->hcd.state = USB_STATE_RUNNING;
if (!udev) {
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control);
return -ENOMEM;
}
 
udev->speed = USB_SPEED_FULL;
if (hcd_register_root (&ohci->hcd) != 0) {
usb_put_dev (udev);
bus->root_hub = NULL;
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control);
return -ENODEV;
}
 
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
/* an interrupt happens */
 
static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs *regs = ohci->regs;
int ints;
 
/* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
if ((ohci->hcca->done_head != 0)
&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
 
/* cardbus/... hardware gone before remove() */
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
disable (ohci);
ohci_dbg (ohci, "device removed!\n");
return;
 
/* interrupt for some other device? */
} else if ((ints &= readl (&regs->intrenable)) == 0) {
return;
}
 
if (ints & OHCI_INTR_UE) {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
// e.g. due to PCI Master/Target Abort
 
ohci_dump (ohci, 1);
hc_reset (ohci);
}
if (ints & OHCI_INTR_WDH) {
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrenable);
}
/* could track INTR_SO to reduce available PCI/... bandwidth */
 
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
* when there's still unlinking to be done (next frame).
*/
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HCD_IS_RUNNING(ohci->hcd.state))
writel (OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
 
if (HCD_IS_RUNNING(ohci->hcd.state)) {
writel (ints, &regs->intrstatus);
writel (OHCI_INTR_MIE, &regs->intrenable);
// flush those pci writes
(void) readl (&ohci->regs->control);
}
}
 
/*-------------------------------------------------------------------------*/
 
static void ohci_stop (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci->hcd.state);
ohci_dump (ohci, 1);
 
if (HCD_IS_RUNNING(ohci->hcd.state))
hc_reset (ohci);
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
}
}
 
/*-------------------------------------------------------------------------*/
 
// FIXME: this restart logic should be generic,
// and handle full hcd state cleanup
 
/* controller died; cleanup debris, then restart */
/* must not be called from interrupt context */
 
#ifdef CONFIG_PM
static int hc_restart (struct ohci_hcd *ohci)
{
int temp;
int i;
 
disable (ohci);
if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
/* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
/* no EDs to remove */
ohci->ed_rm_list = NULL;
 
/* empty control and bulk lists */
ohci->ed_controltail = NULL;
ohci->ed_bulktail = NULL;
 
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
ohci_err (ohci, "can't restart, %d\n", temp);
return temp;
} else
ohci_dbg (ohci, "restart complete\n");
return 0;
}
#endif
 
/*-------------------------------------------------------------------------*/
 
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_INFO);
MODULE_LICENSE ("GPL");
 
#ifdef CONFIG_PCI
#include "ohci-pci.c"
#endif
 
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
#endif
 
#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111))
#error "missing bus glue for ohci-hcd"
#endif
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
* [ (C) Copyright 1999 Linus Torvalds ]
* [ (C) Copyright 1999 Gregory P. Smith]
*
*
* OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller
* interfaces (though some non-x86 Intel chips use it). It supports
* smarter hardware than UHCI. A download link for the spec available
* through the http://www.usb.org website.
*
* History:
*
* 2003/02/24 show registers in sysfs (Kevin Brosius)
*
* 2002/09/03 get rid of ed hashtables, rework periodic scheduling and
* bandwidth accounting; if debugging, show schedules in driverfs
* 2002/07/19 fixes to management of ED and schedule state.
* 2002/06/09 SA-1111 support (Christopher Hoover)
* 2002/06/01 remember frame when HC won't see EDs any more; use that info
* to fix urb unlink races caused by interrupt latency assumptions;
* minor ED field and function naming updates
* 2002/01/18 package as a patch for 2.5.3; this should match the
* 2.4.17 kernel modulo some bugs being fixed.
*
* 2001/10/18 merge pmac cleanup (Benjamin Herrenschmidt) and bugfixes
* from post-2.4.5 patches.
* 2001/09/20 URB_ZERO_PACKET support; hcca_dma portability, OPTi warning
* 2001/09/07 match PCI PM changes, errnos from Linus' tree
* 2001/05/05 fork 2.4.5 version into "hcd" framework, cleanup, simplify;
* pbook pci quirks gone (please fix pbook pci sw!) (db)
*
* 2001/04/08 Identify version on module load (gb)
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
pci_map_single (db)
* 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
* 2001/03/07 hcca allocation uses pci_alloc_consistent_usb (Steve Longerbeam)
*
* 2000/09/26 fixed races in removing the private portion of the urb
* 2000/09/07 disable bulk and control lists when unlinking the last
* endpoint descriptor in order to avoid unrecoverable errors on
* the Lucent chips. (rwc@sgi)
* 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some
* urb unlink probs, indentation fixes
* 2000/08/11 various oops fixes mostly affecting iso and cleanup from
* device unplugs.
* 2000/06/28 use PCI hotplug framework, for better power management
* and for Cardbus support (David Brownell)
* 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling
* when the controller loses power; handle UE; cleanup; ...
*
* v5.2 1999/12/07 URB 3rd preview,
* v5.1 1999/11/30 URB 2nd preview, cpia, (usb-scsi)
* v5.0 1999/11/22 URB Technical preview, Paul Mackerras powerbook susp/resume
* i386: HUB, Keyboard, Mouse, Printer
*
* v4.3 1999/10/27 multiple HCs, bulk_request
* v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
* v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
* v4.0 1999/08/18
* v3.0 1999/06/25
* v2.1 1999/05/09 code clean up
* v2.0 1999/05/04
* v1.0 1999/04/27 initial release
*
* This file is licenced under the GPL.
*/
#include <linuxcomp.h>
 
#include <linux/config.h>
 
#ifdef CONFIG_USB_DEBUG
# define DEBUG
#else
# undef DEBUG
#endif
 
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h>
#include "../core/hcd.h"
 
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
 
 
#define DRIVER_VERSION "2003 Oct 13"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
/*-------------------------------------------------------------------------*/
 
//#define OHCI_VERBOSE_DEBUG /* not always helpful */
 
/* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT \
(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
 
#define OHCI_UNLINK_TIMEOUT (HZ / 10)
 
/*-------------------------------------------------------------------------*/
 
static const char hcd_name [] = "ohci_hcd";
 
#include "ohci.h"
 
static inline void disable (struct ohci_hcd *ohci)
{
ohci->hcd.state = USB_STATE_HALT;
}
 
#include "ohci-hub.c"
#include "ohci-dbg.c"
#include "ohci-mem.c"
#include "ohci-q.c"
 
/*-------------------------------------------------------------------------*/
 
/*
* queue up an urb for anything except the root hub
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
struct urb *urb,
int mem_flags
) {
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ed *ed;
urb_priv_t *urb_priv;
unsigned int pipe = urb->pipe;
int i, size = 0;
unsigned long flags;
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))
return -ENOMEM;
 
/* for the private part of the URB we need the number of TDs (size) */
switch (ed->type) {
case PIPE_CONTROL:
/* td_submit_urb() doesn't yet handle these */
if (urb->transfer_buffer_length > 4096)
return -EMSGSIZE;
 
/* 1 TD for setup, 1 for ACK, plus ... */
size = 2;
/* FALLTHROUGH */
// case PIPE_INTERRUPT:
// case PIPE_BULK:
default:
/* one TD for every 4096 Bytes (can be upto 8K) */
size += urb->transfer_buffer_length / 4096;
/* ... and for any remaining bytes ... */
if ((urb->transfer_buffer_length % 4096) != 0)
size++;
/* ... and maybe a zero length packet to wrap it up */
if (size == 0)
size++;
else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
&& (urb->transfer_buffer_length
% usb_maxpacket (urb->dev, pipe,
usb_pipeout (pipe))) == 0)
size++;
break;
case PIPE_ISOCHRONOUS: /* number of packets from URB */
size = urb->number_of_packets;
break;
}
 
/* allocate the private part of the URB */
urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
mem_flags);
if (!urb_priv)
return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
/* fill the private part of the URB */
urb_priv->length = size;
urb_priv->ed = ed;
 
/* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) {
urb_priv->td [i] = td_alloc (ohci, mem_flags);
if (!urb_priv->td [i]) {
urb_priv->length = i;
urb_free_priv (ohci, urb_priv);
return -ENOMEM;
}
}
 
spin_lock_irqsave (&ohci->lock, flags);
 
/* don't submit to a dead HC */
if (!HCD_IS_RUNNING(ohci->hcd.state)) {
retval = -ENODEV;
goto fail;
}
 
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
if (retval < 0)
goto fail;
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = le16_to_cpu (ohci->hcca->frame_no);
 
/* delay a few frames before the first TD */
frame += max_t (u16, 8, ed->interval);
frame &= ~(ed->interval - 1);
frame |= ed->branch;
urb->start_frame = frame;
 
/* yes, only URB_ISO_ASAP is supported, and
* urb->start_frame is never used as input.
*/
}
} else if (ed->type == PIPE_ISOCHRONOUS)
urb->start_frame = ed->last_iso + ed->interval;
 
/* fill the TDs and link them to the ed; and
* enable that part of the schedule, if needed
* and update count of queued periodic urbs
*/
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
 
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
spin_unlock_irqrestore (&ohci->lock, flags);
return retval;
}
 
/*
* decouple the URB from the HC queues (TDs, urb_priv); it's
* already marked using urb->status. reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
#endif
 
spin_lock_irqsave (&ohci->lock, flags);
if (HCD_IS_RUNNING(ohci->hcd.state)) {
urb_priv_t *urb_priv;
 
/* Unless an IRQ completed the unlink while it was being
* handed to us, flag it for unlink and giveback, and force
* some upcoming INTR_SF to call finish_unlinks()
*/
urb_priv = urb->hcpriv;
if (urb_priv) {
if (urb_priv->ed->state == ED_OPER)
start_urb_unlink (ohci, urb_priv->ed);
}
} else {
/*
* with HC dead, we won't respect hc queue pointers
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv) {
spin_unlock (&ohci->lock);
finish_urb (ohci, urb, NULL);
spin_lock (&ohci->lock);
}
}
spin_unlock_irqrestore (&ohci->lock, flags);
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
/* frees config/altsetting state for endpoints,
* including ED memory, dummy TD, and bulk/intr data toggle
*/
 
static void
ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int epnum = ep & USB_ENDPOINT_NUMBER_MASK;
unsigned long flags;
struct ed *ed;
unsigned limit = 1000;
 
/* ASSERT: any requests/urbs are being unlinked */
/* ASSERT: nobody can be submitting urbs for this any more */
 
epnum <<= 1;
if (epnum != 0 && !(ep & USB_DIR_IN))
epnum |= 1;
 
rescan:
spin_lock_irqsave (&ohci->lock, flags);
ed = dev->ep [epnum];
if (!ed)
goto done;
 
if (!HCD_IS_RUNNING (ohci->hcd.state))
ed->state = ED_IDLE;
switch (ed->state) {
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
WARN_ON (limit-- == 0);
spin_unlock_irqrestore (&ohci->lock, flags);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (1);
goto rescan;
case ED_IDLE: /* fully unlinked */
if (list_empty (&ed->td_list)) {
td_free (ohci, ed->dummy);
ed_free (ohci, ed);
break;
}
/* else FALL THROUGH */
default:
/* caller was supposed to have unlinked any requests;
* that's not our job. can't recover; must leak ed.
*/
ohci_err (ohci, "leak ed %p (#%d) state %d%s\n",
ed, epnum, ed->state,
list_empty (&ed->td_list) ? "" : " (has tds)");
td_free (ohci, ed->dummy);
break;
}
dev->ep [epnum] = 0;
done:
spin_unlock_irqrestore (&ohci->lock, flags);
return;
}
 
static int ohci_get_frame (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
return le16_to_cpu (ohci->hcca->frame_no);
}
 
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
 
/* reset the HC and BUS */
 
static int hc_reset (struct ohci_hcd *ohci)
{
u32 temp;
 
/* SMM owns the HC? not for long!
* On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
*/
#ifndef __hppa__
if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
 
/* this timeout is arbitrary. we make it long, so systems
* depending on usb keyboards may be usable even if the
* BIOS/SMM code seems pretty broken.
*/
temp = 500; /* arbitrary: five seconds */
 
writel (OHCI_INTR_OC, &ohci->regs->intrenable);
writel (OHCI_OCR, &ohci->regs->cmdstatus);
while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
if (--temp == 0) {
ohci_err (ohci, "USB HC TakeOver failed!\n");
return -1;
}
}
}
#endif
 
/* Disable HC interrupts */
writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
ohci_dbg (ohci, "reset, control = 0x%x\n",
readl (&ohci->regs->control));
 
/* Reset USB (needed by some controllers); RemoteWakeupConnected
* saved if boot firmware (BIOS/SMM/...) told us it's connected
*/
ohci->hc_control = readl (&ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
writel (ohci->hc_control, &ohci->regs->control);
// flush those pci writes
(void) readl (&ohci->regs->control);
wait_ms (50);
 
/* HC Reset requires max 10 us delay */
writel (OHCI_HCR, &ohci->regs->cmdstatus);
temp = 30; /* ... allow extra time */
while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--temp == 0) {
ohci_err (ohci, "USB HC reset timed out!\n");
return -1;
}
udelay (1);
}
 
/* now we're in the SUSPEND state ... must go OPERATIONAL
* within 2msec else HC enters RESUME
*
* ... but some hardware won't init fmInterval "by the book"
* (SiS, OPTi ...), so reset again instead. SiS doesn't need
* this if we write fmInterval after we're OPERATIONAL.
*/
writel (ohci->hc_control, &ohci->regs->control);
// flush those pci writes
(void) readl (&ohci->regs->control);
 
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
#define FI 0x2edf /* 12000 bits per frame (-1) */
#define LSTHRESH 0x628 /* lowspeed bit threshold */
 
/* Start an OHCI controller, set the BUS operational
* enable interrupts
* connect the virtual root hub
*/
static int hc_start (struct ohci_hcd *ohci)
{
u32 mask, tmp;
struct usb_device *udev;
struct usb_bus *bus;
 
spin_lock_init (&ohci->lock);
disable (ohci);
 
/* Tell the controller where the control and bulk lists are
* The lists are empty now. */
writel (0, &ohci->regs->ed_controlhead);
writel (0, &ohci->regs->ed_bulkhead);
 
/* a reset clears this */
writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
 
/* force default fmInterval (we won't adjust it); init thresholds
* for last FS and LS packets, reserve 90% for periodic.
*/
writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval);
writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);
writel (LSTHRESH, &ohci->regs->lsthresh);
 
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
*/
if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
|| !readl (&ohci->regs->periodicstart)) {
ohci_err (ohci, "init err\n");
return -EOVERFLOW;
}
 
/* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
writel (ohci->hc_control, &ohci->regs->control);
ohci->hcd.state = USB_STATE_RUNNING;
 
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable);
 
/* handle root hub init quirks ... */
tmp = roothub_a (ohci);
tmp &= ~(RH_A_PSM | RH_A_OCPM);
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
/* NSC 87560 and maybe others */
tmp |= RH_A_NOCP;
tmp &= ~(RH_A_POTPGT | RH_A_NPS);
} else {
/* hub power always on; required for AMD-756 and some
* Mac platforms, use this mode everywhere by default
*/
tmp |= RH_A_NPS;
}
writel (tmp, &ohci->regs->roothub.a);
writel (RH_HS_LPSC, &ohci->regs->roothub.status);
writel (0, &ohci->regs->roothub.b);
// flush those pci writes
(void) readl (&ohci->regs->control);
 
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
/* connect the virtual root hub */
bus = hcd_to_bus (&ohci->hcd);
bus->root_hub = udev = usb_alloc_dev (NULL, bus);
ohci->hcd.state = USB_STATE_RUNNING;
if (!udev) {
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control);
return -ENOMEM;
}
 
udev->speed = USB_SPEED_FULL;
if (hcd_register_root (&ohci->hcd) != 0) {
usb_put_dev (udev);
bus->root_hub = NULL;
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
writel (ohci->hc_control, &ohci->regs->control);
return -ENODEV;
}
 
return 0;
}
 
/*-------------------------------------------------------------------------*/
 
/* an interrupt happens */
 
static void ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs *regs = ohci->regs;
int ints;
 
/* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
if ((ohci->hcca->done_head != 0)
&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
 
/* cardbus/... hardware gone before remove() */
} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
disable (ohci);
ohci_dbg (ohci, "device removed!\n");
return;
 
/* interrupt for some other device? */
} else if ((ints &= readl (&regs->intrenable)) == 0) {
return;
}
 
if (ints & OHCI_INTR_UE) {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
// e.g. due to PCI Master/Target Abort
 
ohci_dump (ohci, 1);
hc_reset (ohci);
}
if (ints & OHCI_INTR_WDH) {
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrenable);
}
/* could track INTR_SO to reduce available PCI/... bandwidth */
 
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
* when there's still unlinking to be done (next frame).
*/
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no),
ptregs);
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HCD_IS_RUNNING(ohci->hcd.state))
writel (OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
 
if (HCD_IS_RUNNING(ohci->hcd.state)) {
writel (ints, &regs->intrstatus);
writel (OHCI_INTR_MIE, &regs->intrenable);
// flush those pci writes
(void) readl (&ohci->regs->control);
}
}
 
/*-------------------------------------------------------------------------*/
 
static void ohci_stop (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
ohci_dbg (ohci, "stop %s controller (state 0x%02x)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
ohci->hcd.state);
ohci_dump (ohci, 1);
 
if (HCD_IS_RUNNING(ohci->hcd.state))
hc_reset (ohci);
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
ohci->hcca, ohci->hcca_dma);
ohci->hcca = NULL;
ohci->hcca_dma = 0;
}
}
 
/*-------------------------------------------------------------------------*/
 
// FIXME: this restart logic should be generic,
// and handle full hcd state cleanup
 
/* controller died; cleanup debris, then restart */
/* must not be called from interrupt context */
 
#ifdef CONFIG_PM
static int hc_restart (struct ohci_hcd *ohci)
{
int temp;
int i;
 
disable (ohci);
if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
/* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
/* no EDs to remove */
ohci->ed_rm_list = NULL;
 
/* empty control and bulk lists */
ohci->ed_controltail = NULL;
ohci->ed_bulktail = NULL;
 
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
ohci_err (ohci, "can't restart, %d\n", temp);
return temp;
} else
ohci_dbg (ohci, "restart complete\n");
return 0;
}
#endif
 
/*-------------------------------------------------------------------------*/
 
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_INFO);
MODULE_LICENSE ("GPL");
 
#ifdef CONFIG_PCI
#include "ohci-pci.c"
#endif
 
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
#endif
 
#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111))
#error "missing bus glue for ohci-hcd"
#endif
/shark/trunk/drivers/usb/host/uhci-hcd.c
1,2670 → 1,2675
/*
* Universal Host Controller Interface driver for USB.
*
* Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
*
* (C) Copyright 1999 Linus Torvalds
* (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
* (C) Copyright 1999 Randy Dunlap
* (C) Copyright 1999 Georg Acher, acher@in.tum.de
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
* (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
* people who decided that they want to do the same thing in a
* completely different way.
*
* WARNING! The USB documentation is downright evil. Most of it
* is just crap, written by a committee. You're better off ignoring
* most of it, the important stuff is:
* - the low-level protocol (fairly simple but lots of small details)
* - working around the horridness of the rest
*/
 
#include <linuxcomp.h>
 
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h>
 
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
 
#include "../core/hcd.h"
#include "uhci-hcd.h"
 
#include <linux/pm.h>
 
/*
* Version Information
*/
#define DRIVER_VERSION "v2.1"
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
#define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
/*
* debug = 0, no debugging messages
* debug = 1, dump failed URB's except for stalls
* debug = 2, dump all failed URB's (including stalls)
* show all queues in /proc/driver/uhci/[pci_addr]
* debug = 3, show all TD's in URB's when dumping
*/
#ifdef DEBUG
static int debug = 3;
#else
static int debug = 0;
#endif
MODULE_PARM(debug, "i");
MODULE_PARM_DESC(debug, "Debug level");
static char *errbuf;
#define ERRBUF_LEN (PAGE_SIZE * 8)
 
#include "uhci-hub.c"
#include "uhci-debug.c"
 
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
 
static int uhci_get_current_frame_number(struct uhci_hcd *uhci);
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb);
static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb);
 
static void hc_state_transitions(struct uhci_hcd *uhci);
 
/* If a transfer is still active after this much time, turn off FSBR */
#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */
#define FSBR_DELAY (HZ / 20) /* 50 ms */
 
/* When we timeout an idle transfer for FSBR, we'll switch it over to */
/* depth first traversal. We'll do it in groups of this number of TD's */
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
 
/*
* Technically, updating td->status here is a race, but it's not really a
* problem. The worst that can happen is that we set the IOC bit again
* generating a spurious interrupt. We could fix this by creating another
* QH and leaving the IOC bit always set, but then we would have to play
* games with the FSBR code to make sure we get the correct order in all
* the cases. I don't think it's worth the effort
*/
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
unsigned long flags;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci)
{
unsigned long flags;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC);
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
static inline void uhci_add_complete(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
unsigned long flags;
 
spin_lock_irqsave(&uhci->complete_list_lock, flags);
list_add_tail(&urbp->complete_list, &uhci->complete_list);
spin_unlock_irqrestore(&uhci->complete_list_lock, flags);
}
 
static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
{
dma_addr_t dma_handle;
struct uhci_td *td;
 
td = pci_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle);
if (!td)
return NULL;
 
td->dma_handle = dma_handle;
 
td->link = UHCI_PTR_TERM;
td->buffer = 0;
 
td->frame = -1;
td->dev = dev;
 
INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list);
 
usb_get_dev(dev);
 
return td;
}
 
static inline void uhci_fill_td(struct uhci_td *td, __u32 status,
__u32 token, __u32 buffer)
{
td->status = cpu_to_le32(status);
td->token = cpu_to_le32(token);
td->buffer = cpu_to_le32(buffer);
}
 
/*
* We insert Isochronous URB's directly into the frame list at the beginning
*/
static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
{
unsigned long flags;
 
framenum %= UHCI_NUMFRAMES;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
td->frame = framenum;
 
/* Is there a TD already mapped there? */
if (uhci->fl->frame_cpu[framenum]) {
struct uhci_td *ftd, *ltd;
 
ftd = uhci->fl->frame_cpu[framenum];
ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
 
list_add_tail(&td->fl_list, &ftd->fl_list);
 
td->link = ltd->link;
mb();
ltd->link = cpu_to_le32(td->dma_handle);
} else {
td->link = uhci->fl->frame[framenum];
mb();
uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
uhci->fl->frame_cpu[framenum] = td;
}
 
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
{
unsigned long flags;
 
/* If it's not inserted, don't remove it */
spin_lock_irqsave(&uhci->frame_list_lock, flags);
if (td->frame == -1 && list_empty(&td->fl_list))
goto out;
 
if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
if (list_empty(&td->fl_list)) {
uhci->fl->frame[td->frame] = td->link;
uhci->fl->frame_cpu[td->frame] = NULL;
} else {
struct uhci_td *ntd;
 
ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
uhci->fl->frame_cpu[td->frame] = ntd;
}
} else {
struct uhci_td *ptd;
 
ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list);
ptd->link = td->link;
}
 
mb();
td->link = UHCI_PTR_TERM;
 
list_del_init(&td->fl_list);
td->frame = -1;
 
out:
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
/*
* Inserts a td into qh list at the top.
*/
static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td, *ptd;
 
if (list_empty(&urbp->td_list))
return;
 
head = &urbp->td_list;
tmp = head->next;
 
/* Ordering isn't important here yet since the QH hasn't been */
/* inserted into the schedule yet */
td = list_entry(tmp, struct uhci_td, list);
 
/* Add the first TD to the QH element pointer */
qh->element = cpu_to_le32(td->dma_handle) | breadth;
 
ptd = td;
 
/* Then link the rest of the TD's */
tmp = tmp->next;
while (tmp != head) {
td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
ptd->link = cpu_to_le32(td->dma_handle) | breadth;
 
ptd = td;
}
 
ptd->link = UHCI_PTR_TERM;
}
 
static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
{
if (!list_empty(&td->list))
dbg("td %p is still in list!", td);
if (!list_empty(&td->remove_list))
dbg("td %p still in remove_list!", td);
if (!list_empty(&td->fl_list))
dbg("td %p is still in fl_list!", td);
 
if (td->dev)
usb_put_dev(td->dev);
 
pci_pool_free(uhci->td_pool, td, td->dma_handle);
}
 
static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
{
dma_addr_t dma_handle;
struct uhci_qh *qh;
 
qh = pci_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle);
if (!qh)
return NULL;
 
qh->dma_handle = dma_handle;
 
qh->element = UHCI_PTR_TERM;
qh->link = UHCI_PTR_TERM;
 
qh->dev = dev;
qh->urbp = NULL;
 
INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list);
 
usb_get_dev(dev);
 
return qh;
}
 
static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
if (!list_empty(&qh->list))
dbg("qh %p list not empty!", qh);
if (!list_empty(&qh->remove_list))
dbg("qh %p still in remove_list!", qh);
 
if (qh->dev)
usb_put_dev(qh->dev);
 
pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
 
/*
* Append this urb's qh after the last qh in skelqh->list
* MUST be called with uhci->frame_list_lock acquired
*
* Note that urb_priv.queue_list doesn't have a separate queue head;
* it's a ring with every element "live".
*/
static void _uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct list_head *tmp;
struct uhci_qh *lqh;
 
/* Grab the last QH */
lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
/*
* Patch this endpoint's URB's QHs to point to the next skelqh:
* skelqh --> ... lqh --> newqh --> next skelqh
* Do this first, so the HC always sees the right QH after this one.
*/
list_for_each (tmp, &urbp->queue_list) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
 
turbp->qh->link = lqh->link;
}
urbp->qh->link = lqh->link;
wmb(); /* Ordering is important */
 
/*
* Patch QHs for previous endpoint's queued URBs? HC goes
* here next, not to the next skelqh it now points to.
*
* lqh --> td ... --> qh ... --> td --> qh ... --> td
* | | |
* v v v
* +<----------------+-----------------+
* v
* newqh --> td ... --> td
* |
* v
* ...
*
* The HC could see (and use!) any of these as we write them.
*/
if (lqh->urbp) {
list_for_each (tmp, &lqh->urbp->queue_list) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
 
turbp->qh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
}
}
lqh->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
 
list_add_tail(&urbp->qh->list, &skelqh->list);
}
 
static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct urb *urb)
{
unsigned long flags;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
_uhci_insert_qh(uhci, skelqh, urb);
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
/*
* Start removal of QH from schedule; it finishes next frame.
* TDs should be unlinked before this is called.
*/
static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
unsigned long flags;
struct uhci_qh *pqh;
 
if (!qh)
return;
 
qh->urbp = NULL;
 
/*
* Only go through the hoops if it's actually linked in
* Queued QHs are removed in uhci_delete_queued_urb,
* since (for queued URBs) the pqh is pointed to the next
* QH in the queue, not the next endpoint's QH.
*/
spin_lock_irqsave(&uhci->frame_list_lock, flags);
if (!list_empty(&qh->list)) {
pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
if (pqh->urbp) {
struct list_head *head, *tmp;
 
head = &pqh->urbp->queue_list;
tmp = head->next;
while (head != tmp) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
 
tmp = tmp->next;
 
turbp->qh->link = qh->link;
}
}
 
pqh->link = qh->link;
mb();
/* Leave qh->link in case the HC is on the QH now, it will */
/* continue the rest of the schedule */
qh->element = UHCI_PTR_TERM;
 
list_del_init(&qh->list);
}
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 
spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
/* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the QH */
if (list_empty(&uhci->qh_remove_list))
uhci_set_next_interrupt(uhci);
 
list_add(&qh->remove_list, &uhci->qh_remove_list);
 
spin_unlock_irqrestore(&uhci->qh_remove_list_lock, flags);
}
 
static int uhci_fixup_toggle(struct urb *urb, unsigned int toggle)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct list_head *head, *tmp;
 
head = &urbp->td_list;
tmp = head->next;
while (head != tmp) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
if (toggle)
td->token |= cpu_to_le32(TD_TOKEN_TOGGLE);
else
td->token &= ~cpu_to_le32(TD_TOKEN_TOGGLE);
 
 
toggle ^= 1;
}
 
return toggle;
}
 
/* This function will append one URB's QH to another URB's QH. This is for */
/* queuing interrupt, control or bulk transfers */
static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, struct urb *urb)
{
struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
struct list_head *tmp;
struct uhci_td *lltd;
unsigned long flags;
 
eurbp = eurb->hcpriv;
urbp = urb->hcpriv;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
/* Find the first URB in the queue */
if (eurbp->queued) {
struct list_head *head = &eurbp->queue_list;
 
tmp = head->next;
while (tmp != head) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
 
if (!turbp->queued)
break;
 
tmp = tmp->next;
}
} else
tmp = &eurbp->queue_list;
 
furbp = list_entry(tmp, struct urb_priv, queue_list);
lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
 
lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
 
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
uhci_fixup_toggle(urb, uhci_toggle(td_token(lltd)) ^ 1));
 
/* All qh's in the queue need to link to the next queue */
urbp->qh->link = eurbp->qh->link;
 
mb(); /* Make sure we flush everything */
 
lltd->link = cpu_to_le32(urbp->qh->dma_handle) | UHCI_PTR_QH;
 
list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
urbp->queued = 1;
 
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
static void uhci_delete_queued_urb(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp, *nurbp;
struct list_head *head, *tmp;
struct urb_priv *purbp;
struct uhci_td *pltd;
unsigned int toggle;
unsigned long flags;
 
urbp = urb->hcpriv;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
if (list_empty(&urbp->queue_list))
goto out;
 
nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
 
/* Fix up the toggle for the next URB's */
if (!urbp->queued)
/* We just set the toggle in uhci_unlink_generic */
toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
else {
/* If we're in the middle of the queue, grab the toggle */
/* from the TD previous to us */
purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
queue_list);
 
pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
 
toggle = uhci_toggle(td_token(pltd)) ^ 1;
}
 
head = &urbp->queue_list;
tmp = head->next;
while (head != tmp) {
struct urb_priv *turbp;
 
turbp = list_entry(tmp, struct urb_priv, queue_list);
 
tmp = tmp->next;
 
if (!turbp->queued)
break;
 
toggle = uhci_fixup_toggle(turbp->urb, toggle);
}
 
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
 
if (!urbp->queued) {
struct uhci_qh *pqh;
 
nurbp->queued = 0;
 
/*
* Fixup the previous QH's queue to link to the new head
* of this queue.
*/
pqh = list_entry(urbp->qh->list.prev, struct uhci_qh, list);
 
if (pqh->urbp) {
struct list_head *head, *tmp;
 
head = &pqh->urbp->queue_list;
tmp = head->next;
while (head != tmp) {
struct urb_priv *turbp =
list_entry(tmp, struct urb_priv, queue_list);
 
tmp = tmp->next;
 
turbp->qh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
}
}
 
pqh->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
 
list_add_tail(&nurbp->qh->list, &urbp->qh->list);
list_del_init(&urbp->qh->list);
} else {
/* We're somewhere in the middle (or end). A bit trickier */
/* than the head scenario */
purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
queue_list);
 
pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
if (nurbp->queued)
pltd->link = cpu_to_le32(nurbp->qh->dma_handle) | UHCI_PTR_QH;
else
/* The next URB happens to be the beginning, so */
/* we're the last, end the chain */
pltd->link = UHCI_PTR_TERM;
}
 
list_del_init(&urbp->queue_list);
 
out:
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
extern void* malloc(int size);
 
static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp;
 
urbp = malloc(sizeof(struct urb_priv)); //**kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
if (!urbp) {
err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
return NULL;
}
 
memset((void *)urbp, 0, sizeof(*urbp));
 
urbp->inserttime = jiffies26;
urbp->fsbrtime = jiffies26;
urbp->urb = urb;
urbp->dev = urb->dev;
INIT_LIST_HEAD(&urbp->td_list);
INIT_LIST_HEAD(&urbp->queue_list);
INIT_LIST_HEAD(&urbp->complete_list);
INIT_LIST_HEAD(&urbp->urb_list);
 
list_add_tail(&urbp->urb_list, &uhci->urb_list);
 
urb->hcpriv = urbp;
 
return urbp;
}
 
/*
* MUST be called with urb->lock acquired
*/
static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
td->urb = urb;
 
list_add_tail(&td->list, &urbp->td_list);
}
 
/*
* MUST be called with urb->lock acquired
*/
static void uhci_remove_td_from_urb(struct uhci_td *td)
{
if (list_empty(&td->list))
return;
 
list_del_init(&td->list);
 
td->urb = NULL;
}
 
/*
* MUST be called with urb->lock acquired
*/
static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *head, *tmp;
struct urb_priv *urbp;
unsigned long flags;
 
urbp = (struct urb_priv *)urb->hcpriv;
if (!urbp)
return;
 
if (!list_empty(&urbp->urb_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->urb_list or uhci->remove_list", urb);
 
if (!list_empty(&urbp->complete_list))
warn("uhci_destroy_urb_priv: urb %p still on uhci->complete_list", urb);
 
spin_lock_irqsave(&uhci->td_remove_list_lock, flags);
 
/* Check to see if the remove list is empty. Set the IOC bit */
/* to force an interrupt so we can remove the TD's*/
if (list_empty(&uhci->td_remove_list))
uhci_set_next_interrupt(uhci);
 
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
uhci_remove_td_from_urb(td);
uhci_remove_td(uhci, td);
list_add(&td->remove_list, &uhci->td_remove_list);
}
 
spin_unlock_irqrestore(&uhci->td_remove_list_lock, flags);
 
urb->hcpriv = NULL;
//**kmem_cache_free(uhci_up_cachep, urbp);
free(urbp);
}
 
static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb)
{
unsigned long flags;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {
urbp->fsbr = 1;
if (!uhci->fsbr++ && !uhci->fsbrtimeout)
uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_hs_control_qh->dma_handle) | UHCI_PTR_QH;
}
 
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb)
{
unsigned long flags;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {
urbp->fsbr = 0;
if (!--uhci->fsbr)
uhci->fsbrtimeout = jiffies26 + FSBR_DELAY;
}
 
spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
}
 
/*
* Map status to standard result codes
*
* <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)]
* <dir_out> is True for output TDs and False for input TDs.
*/
static int uhci_map_status(int status, int dir_out)
{
if (!status)
return 0;
if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */
return -EPROTO;
if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */
if (dir_out)
return -ETIMEDOUT;
else
return -EILSEQ;
}
if (status & TD_CTRL_NAK) /* NAK */
return -ETIMEDOUT;
if (status & TD_CTRL_BABBLE) /* Babble */
return -EOVERFLOW;
if (status & TD_CTRL_DBUFERR) /* Buffer error */
return -ENOSR;
if (status & TD_CTRL_STALLED) /* Stalled */
return -EPIPE;
if (status & TD_CTRL_ACTIVE) /* Active */
return 0;
 
return -EINVAL;
}
 
/*
* Control transfers
*/
static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct uhci_td *td;
struct uhci_qh *qh, *skelqh;
unsigned long destination, status;
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
dma_addr_t data = urb->transfer_dma;
 
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
 
/* 3 errors */
status = TD_CTRL_ACTIVE | uhci_maxerr(3);
if (urb->dev->speed == USB_SPEED_LOW)
status |= TD_CTRL_LS;
 
/*
* Build the TD for the control request
*/
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | uhci_explen(7),
urb->setup_dma);
 
/*
* If direction is "send", change the frame from SETUP (0x2D)
* to OUT (0xE1). Else change it from SETUP to IN (0x69).
*/
destination ^= (USB_PID_SETUP ^ usb_packetid(urb->pipe));
 
if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
status |= TD_CTRL_SPD;
 
/*
* Build the DATA TD's
*/
while (len > 0) {
int pktsze = len;
 
if (pktsze > maxsze)
pktsze = maxsze;
 
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
/* Alternate Data0/1 (start with Data1) */
destination ^= TD_TOKEN_TOGGLE;
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
data);
 
data += pktsze;
len -= pktsze;
}
 
/*
* Build the final TD for control status
*/
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
/*
* It's IN if the pipe is an output pipe or we're not expecting
* data back.
*/
destination &= ~TD_TOKEN_PID_MASK;
if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
destination |= USB_PID_IN;
else
destination |= USB_PID_OUT;
 
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
 
status &= ~TD_CTRL_SPD;
 
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
 
qh = uhci_alloc_qh(uhci, urb->dev);
if (!qh)
return -ENOMEM;
 
urbp->qh = qh;
qh->urbp = urbp;
 
uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
 
/* Low speed transfers get a different queue, and won't hog the bus */
if (urb->dev->speed == USB_SPEED_LOW)
skelqh = uhci->skel_ls_control_qh;
else {
skelqh = uhci->skel_hs_control_qh;
uhci_inc_fsbr(uhci, urb);
}
 
if (eurb)
uhci_append_queued_urb(uhci, eurb, urb);
else
uhci_insert_qh(uhci, skelqh, urb);
 
return -EINPROGRESS;
}
 
/*
* If control was short, then end status packet wasn't sent, so this
* reorganize s so it's sent to finish the transfer. The original QH is
* removed from the skel and discarded; all TDs except the last (status)
* are deleted; the last (status) TD is put on a new QH which is reinserted
* into the skel. Since the last TD and urb_priv are reused, the TD->link
* and urb_priv maintain any queued QHs.
*/
static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
urbp->short_control_packet = 1;
 
/* Create a new QH to avoid pointer overwriting problems */
uhci_remove_qh(uhci, urbp->qh);
 
/* Delete all of the TD's except for the status TD at the end */
head = &urbp->td_list;
tmp = head->next;
while (tmp != head && tmp->next != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
uhci_remove_td_from_urb(td);
uhci_remove_td(uhci, td);
uhci_free_td(uhci, td);
}
 
urbp->qh = uhci_alloc_qh(uhci, urb->dev);
if (!urbp->qh) {
err("unable to allocate new QH for control retrigger");
return -ENOMEM;
}
 
urbp->qh->urbp = urbp;
 
/* One TD, who cares about Breadth first? */
uhci_insert_tds_in_qh(urbp->qh, urb, UHCI_PTR_DEPTH);
 
/* Low speed transfers get a different queue */
if (urb->dev->speed == USB_SPEED_LOW)
uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
else
uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 
return -EINPROGRESS;
}
 
 
static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
unsigned int status;
int ret = 0;
 
if (list_empty(&urbp->td_list))
return -EINVAL;
 
head = &urbp->td_list;
if (urbp->short_control_packet) {
tmp = head->prev;
goto status_phase;
}
tmp = head->next;
td = list_entry(tmp, struct uhci_td, list);
 
/* The first TD is the SETUP phase, check the status, but skip */
/* the count */
status = uhci_status_bits(td_status(td));
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
 
if (status)
goto td_error;
 
urb->actual_length = 0;
 
/* The rest of the TD's (but the last) are data */
tmp = tmp->next;
while (tmp != head && tmp->next != head) {
td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
status = uhci_status_bits(td_status(td));
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
 
urb->actual_length += uhci_actual_length(td_status(td));
 
if (status)
goto td_error;
 
/* Check to see if we received a short packet */
if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) {
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
ret = -EREMOTEIO;
goto err;
}
 
if (uhci_packetid(td_token(td)) == USB_PID_IN)
return usb_control_retrigger_status(uhci, urb);
else
return 0;
}
}
 
status_phase:
td = list_entry(tmp, struct uhci_td, list);
 
/* Control status phase */
status = td_status(td);
 
#ifdef I_HAVE_BUGGY_APC_BACKUPS
/* APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of the amount */
/* we requested */
if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */
status & TD_CTRL_ACTIVE &&
status & TD_CTRL_NAK)
return 0;
#endif
 
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
 
if (uhci_status_bits(status))
goto td_error;
 
return 0;
 
td_error:
ret = uhci_map_status(status, uhci_packetout(td_token(td)));
 
err:
if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */
dbg("uhci_result_control() failed with status %x", status);
 
if (errbuf) {
/* Print the chain for debugging purposes */
uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
 
lprintk(errbuf);
}
}
 
return ret;
}
 
/*
* Common submit for bulk and interrupt
*/
static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh)
{
struct uhci_td *td;
struct uhci_qh *qh;
unsigned long destination, status;
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
dma_addr_t data = urb->transfer_dma;
 
if (len < 0)
return -EINVAL;
 
/* The "pipe" thing contains the destination in bits 8--18 */
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
status = uhci_maxerr(3) | TD_CTRL_ACTIVE;
if (urb->dev->speed == USB_SPEED_LOW)
status |= TD_CTRL_LS;
if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
status |= TD_CTRL_SPD;
 
/*
* Build the DATA TD's
*/
do { /* Allow zero length packets */
int pktsze = len;
 
if (pktsze > maxsze)
pktsze = maxsze;
 
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
data);
 
data += pktsze;
len -= maxsze;
 
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
} while (len > 0);
 
/*
* URB_ZERO_PACKET means adding a 0-length packet, if direction
* is OUT and the transfer_length was an exact multiple of maxsze,
* hence (len = transfer_length - N * maxsze) == 0
* however, if transfer_length == 0, the zero packet was already
* prepared above.
*/
if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
!len && urb->transfer_buffer_length) {
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
data);
 
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe));
}
 
/* Set the flag on the last packet */
td->status |= cpu_to_le32(TD_CTRL_IOC);
 
qh = uhci_alloc_qh(uhci, urb->dev);
if (!qh)
return -ENOMEM;
 
urbp->qh = qh;
qh->urbp = urbp;
 
/* Always breadth first */
uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);
 
if (eurb)
uhci_append_queued_urb(uhci, eurb, urb);
else
uhci_insert_qh(uhci, skelqh, urb);
 
return -EINPROGRESS;
}
 
/*
* Common result for bulk and interrupt
*/
static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = urb->hcpriv;
struct uhci_td *td;
unsigned int status = 0;
int ret = 0;
 
urb->actual_length = 0;
 
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
status = uhci_status_bits(td_status(td));
if (status & TD_CTRL_ACTIVE)
return -EINPROGRESS;
 
urb->actual_length += uhci_actual_length(td_status(td));
 
if (status)
goto td_error;
 
if (uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td))) {
if (urb->transfer_flags & URB_SHORT_NOT_OK) {
ret = -EREMOTEIO;
goto err;
} else
return 0;
}
}
 
return 0;
 
td_error:
ret = uhci_map_status(status, uhci_packetout(td_token(td)));
if (ret == -EPIPE)
/* endpoint has stalled - mark it halted */
usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)),
uhci_packetout(td_token(td)));
 
err:
/*
* Enable this chunk of code if you want to see some more debugging.
* But be careful, it has the tendancy to starve out khubd and prevent
* disconnects from happening successfully if you have a slow debug
* log interface (like a serial console.
*/
#if 0
if ((debug == 1 && ret != -EPIPE) || debug > 1) {
/* Some debugging code */
dbg("uhci_result_common() failed with status %x", status);
 
if (errbuf) {
/* Print the chain for debugging purposes */
uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);
 
lprintk(errbuf);
}
}
#endif
return ret;
}
 
static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
{
int ret;
 
/* Can't have low speed bulk transfers */
if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL;
 
ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);
if (ret == -EINPROGRESS)
uhci_inc_fsbr(uhci, urb);
 
return ret;
}
 
static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb)
{
/* USB 1.1 interrupt transfers only involve one packet per interval;
* that's the uhci_submit_common() "breadth first" policy. Drivers
* can submit urbs of any length, but longer ones might need many
* intervals to complete.
*/
return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);
}
 
/*
* Bulk and interrupt use common result
*/
#define uhci_result_bulk uhci_result_common
#define uhci_result_interrupt uhci_result_common
 
/*
* Isochronous transfers
*/
static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end)
{
struct urb *last_urb = NULL;
struct list_head *tmp, *head;
int ret = 0;
 
head = &uhci->urb_list;
tmp = head->next;
while (tmp != head) {
struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list);
struct urb *u = up->urb;
 
tmp = tmp->next;
 
/* look for pending URB's with identical pipe handle */
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
(u->status == -EINPROGRESS) && (u != urb)) {
if (!last_urb)
*start = u->start_frame;
last_urb = u;
}
}
 
if (last_urb) {
*end = (last_urb->start_frame + last_urb->number_of_packets *
last_urb->interval) & (UHCI_NUMFRAMES-1);
ret = 0;
} else
ret = -1; /* no previous urb found */
 
return ret;
}
 
static int isochronous_find_start(struct uhci_hcd *uhci, struct urb *urb)
{
int limits;
unsigned int start = 0, end = 0;
 
if (urb->number_of_packets > 900) /* 900? Why? */
return -EFBIG;
 
limits = isochronous_find_limits(uhci, urb, &start, &end);
 
if (urb->transfer_flags & URB_ISO_ASAP) {
if (limits) {
int curframe;
 
curframe = uhci_get_current_frame_number(uhci) % UHCI_NUMFRAMES;
urb->start_frame = (curframe + 10) % UHCI_NUMFRAMES;
} else
urb->start_frame = end;
} else {
urb->start_frame %= UHCI_NUMFRAMES;
/* FIXME: Sanity check */
}
 
return 0;
}
 
/*
* Isochronous transfers
*/
static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
{
struct uhci_td *td;
int i, ret, frame;
int status, destination;
 
status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
ret = isochronous_find_start(uhci, urb);
if (ret)
return ret;
 
frame = urb->start_frame;
for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
if (!urb->iso_frame_desc[i].length)
continue;
 
td = uhci_alloc_td(uhci, urb->dev);
if (!td)
return -ENOMEM;
 
uhci_add_td_to_urb(urb, td);
uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
urb->transfer_dma + urb->iso_frame_desc[i].offset);
 
if (i + 1 >= urb->number_of_packets)
td->status |= cpu_to_le32(TD_CTRL_IOC);
 
uhci_insert_td_frame_list(uhci, td, frame);
}
 
return -EINPROGRESS;
}
 
static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *tmp, *head;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
int status;
int i, ret = 0;
 
urb->actual_length = 0;
 
i = 0;
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
int actlength;
 
tmp = tmp->next;
 
if (td_status(td) & TD_CTRL_ACTIVE)
return -EINPROGRESS;
 
actlength = uhci_actual_length(td_status(td));
urb->iso_frame_desc[i].actual_length = actlength;
urb->actual_length += actlength;
 
status = uhci_map_status(uhci_status_bits(td_status(td)), usb_pipeout(urb->pipe));
urb->iso_frame_desc[i].status = status;
if (status) {
urb->error_count++;
ret = status;
}
 
i++;
}
 
return ret;
}
 
/*
* MUST be called with uhci->urb_list_lock acquired
*/
static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *tmp, *head;
 
/* We don't match Isoc transfers since they are special */
if (usb_pipeisoc(urb->pipe))
return NULL;
 
head = &uhci->urb_list;
tmp = head->next;
while (tmp != head) {
struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list);
struct urb *u = up->urb;
 
tmp = tmp->next;
 
if (u->dev == urb->dev && u->status == -EINPROGRESS) {
/* For control, ignore the direction */
if (usb_pipecontrol(urb->pipe) &&
(u->pipe & ~USB_DIR_IN) == (urb->pipe & ~USB_DIR_IN))
return u;
else if (u->pipe == urb->pipe)
return u;
}
}
 
return NULL;
}
 
static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
{
int ret = -EINVAL;
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
struct urb *eurb;
int bustime;
 
spin_lock_irqsave(&uhci->urb_list_lock, flags);
 
eurb = uhci_find_urb_ep(uhci, urb);
 
if (!uhci_alloc_urb_priv(uhci, urb)) {
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return -ENOMEM;
}
 
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
ret = uhci_submit_control(uhci, urb, eurb);
break;
case PIPE_INTERRUPT:
if (!eurb) {
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
ret = bustime;
else {
ret = uhci_submit_interrupt(uhci, urb, eurb);
if (ret == -EINPROGRESS)
usb_claim_bandwidth(urb->dev, urb, bustime, 0);
}
} else { /* inherit from parent */
urb->bandwidth = eurb->bandwidth;
ret = uhci_submit_interrupt(uhci, urb, eurb);
}
break;
case PIPE_BULK:
ret = uhci_submit_bulk(uhci, urb, eurb);
break;
case PIPE_ISOCHRONOUS:
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0) {
ret = bustime;
break;
}
 
ret = uhci_submit_isochronous(uhci, urb);
if (ret == -EINPROGRESS)
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
}
 
if (ret != -EINPROGRESS) {
/* Submit failed, so delete it from the urb_list */
struct urb_priv *urbp = urb->hcpriv;
 
list_del_init(&urbp->urb_list);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
uhci_destroy_urb_priv (uhci, urb);
 
return ret;
}
 
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
return 0;
}
 
/*
* Return the result of a transfer
*
* MUST be called with urb_list_lock acquired
*/
static void uhci_transfer_result(struct uhci_hcd *uhci, struct urb *urb)
{
int ret = -EINVAL;
unsigned long flags;
struct urb_priv *urbp;
 
spin_lock_irqsave(&urb->lock, flags);
 
urbp = (struct urb_priv *)urb->hcpriv;
 
if (urb->status != -EINPROGRESS) {
info("uhci_transfer_result: called for URB %p not in flight?", urb);
goto out;
}
 
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
ret = uhci_result_control(uhci, urb);
break;
case PIPE_INTERRUPT:
ret = uhci_result_interrupt(uhci, urb);
break;
case PIPE_BULK:
ret = uhci_result_bulk(uhci, urb);
break;
case PIPE_ISOCHRONOUS:
ret = uhci_result_isochronous(uhci, urb);
break;
}
 
urbp->status = ret;
 
if (ret == -EINPROGRESS)
goto out;
 
switch (usb_pipetype(urb->pipe)) {
case PIPE_CONTROL:
case PIPE_BULK:
case PIPE_ISOCHRONOUS:
/* Release bandwidth for Interrupt or Isoc. transfers */
/* Spinlock needed ? */
if (urb->bandwidth)
usb_release_bandwidth(urb->dev, urb, 1);
uhci_unlink_generic(uhci, urb);
break;
case PIPE_INTERRUPT:
/* Release bandwidth for Interrupt or Isoc. transfers */
/* Make sure we don't release if we have a queued URB */
spin_lock(&uhci->frame_list_lock);
/* Spinlock needed ? */
if (list_empty(&urbp->queue_list) && urb->bandwidth)
usb_release_bandwidth(urb->dev, urb, 0);
else
/* bandwidth was passed on to queued URB, */
/* so don't let usb_unlink_urb() release it */
urb->bandwidth = 0;
spin_unlock(&uhci->frame_list_lock);
uhci_unlink_generic(uhci, urb);
break;
default:
info("uhci_transfer_result: unknown pipe type %d for urb %p\n",
usb_pipetype(urb->pipe), urb);
}
 
/* Remove it from uhci->urb_list */
list_del_init(&urbp->urb_list);
 
uhci_add_complete(uhci, urb);
 
out:
spin_unlock_irqrestore(&urb->lock, flags);
}
 
/*
* MUST be called with urb->lock acquired
*/
static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
{
struct list_head *head, *tmp;
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
int prevactive = 1;
 
/* We can get called when urbp allocation fails, so check */
if (!urbp)
return;
 
uhci_dec_fsbr(uhci, urb); /* Safe since it checks */
 
/*
* Now we need to find out what the last successful toggle was
* so we can update the local data toggle for the next transfer
*
* There's 3 way's the last successful completed TD is found:
*
* 1) The TD is NOT active and the actual length < expected length
* 2) The TD is NOT active and it's the last TD in the chain
* 3) The TD is active and the previous TD is NOT active
*
* Control and Isochronous ignore the toggle, so this is safe
* for all types
*/
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
if (!(td_status(td) & TD_CTRL_ACTIVE) &&
(uhci_actual_length(td_status(td)) < uhci_expected_length(td_token(td)) ||
tmp == head))
usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
uhci_packetout(td_token(td)),
uhci_toggle(td_token(td)) ^ 1);
else if ((td_status(td) & TD_CTRL_ACTIVE) && !prevactive)
usb_settoggle(urb->dev, uhci_endpoint(td_token(td)),
uhci_packetout(td_token(td)),
uhci_toggle(td_token(td)));
 
prevactive = td_status(td) & TD_CTRL_ACTIVE;
}
 
uhci_delete_queued_urb(uhci, urb);
 
/* The interrupt loop will reclaim the QH's */
uhci_remove_qh(uhci, urbp->qh);
urbp->qh = NULL;
}
 
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
struct urb_priv *urbp = urb->hcpriv;
 
/* If this is an interrupt URB that is being killed in urb->complete, */
/* then just set its status and return */
if (!urbp) {
urb->status = -ECONNRESET;
return 0;
}
 
spin_lock_irqsave(&uhci->urb_list_lock, flags);
 
list_del_init(&urbp->urb_list);
 
uhci_unlink_generic(uhci, urb);
 
spin_lock(&uhci->urb_remove_list_lock);
 
/* If we're the first, set the next interrupt bit */
if (list_empty(&uhci->urb_remove_list))
uhci_set_next_interrupt(uhci);
list_add(&urbp->urb_list, &uhci->urb_remove_list);
 
spin_unlock(&uhci->urb_remove_list_lock);
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return 0;
}
 
static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
{
struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
struct list_head *head, *tmp;
int count = 0;
 
uhci_dec_fsbr(uhci, urb);
 
urbp->fsbr_timeout = 1;
 
/*
* Ideally we would want to fix qh->element as well, but it's
* read/write by the HC, so that can introduce a race. It's not
* really worth the hassle
*/
 
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
 
tmp = tmp->next;
 
/*
* Make sure we don't do the last one (since it'll have the
* TERM bit set) as well as we skip every so many TD's to
* make sure it doesn't hog the bandwidth
*/
if (tmp != head && (count % DEPTH_INTERVAL) == (DEPTH_INTERVAL - 1))
td->link |= UHCI_PTR_DEPTH;
 
count++;
}
 
return 0;
}
 
/*
* uhci_get_current_frame_number()
*
* returns the current frame number for a USB bus/controller.
*/
static int uhci_get_current_frame_number(struct uhci_hcd *uhci)
{
return inw(uhci->io_addr + USBFRNUM);
}
 
static int init_stall_timer(struct usb_hcd *hcd);
 
static void stall_callback(unsigned long ptr)
{
struct usb_hcd *hcd = (struct usb_hcd *)ptr;
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct list_head list, *tmp, *head;
unsigned long flags;
 
INIT_LIST_HEAD(&list);
 
spin_lock_irqsave(&uhci->urb_list_lock, flags);
head = &uhci->urb_list;
tmp = head->next;
while (tmp != head) {
struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list);
struct urb *u = up->urb;
 
tmp = tmp->next;
 
spin_lock(&u->lock);
 
/* Check if the FSBR timed out */
if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies26, up->fsbrtime + IDLE_TIMEOUT))
uhci_fsbr_timeout(uhci, u);
 
/* Check if the URB timed out */
if (u->timeout && time_after_eq(jiffies26, up->inserttime + u->timeout))
list_move_tail(&up->urb_list, &list);
 
spin_unlock(&u->lock);
}
spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
head = &list;
tmp = head->next;
while (tmp != head) {
struct urb_priv *up = list_entry(tmp, struct urb_priv, urb_list);
struct urb *u = up->urb;
 
tmp = tmp->next;
 
uhci_urb_dequeue(hcd, u);
}
 
/* Really disable FSBR */
if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies26, uhci->fsbrtimeout)) {
uhci->fsbrtimeout = 0;
uhci->skel_term_qh->link = UHCI_PTR_TERM;
}
 
/* Poll for and perform state transitions */
hc_state_transitions(uhci);
 
init_stall_timer(hcd);
}
 
static int init_stall_timer(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
init_timer(&uhci->stall_timer);
uhci->stall_timer.function = stall_callback;
uhci->stall_timer.data = (unsigned long)hcd;
uhci->stall_timer.expires = jiffies26 + (HZ / 10);
add_timer(&uhci->stall_timer);
 
return 0;
}
 
static void uhci_free_pending_qhs(struct uhci_hcd *uhci)
{
struct list_head *tmp, *head;
unsigned long flags;
&n