*
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
-#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
+#include <asm/semaphore.h>
#include <linux/usb.h>
-#include <linux/usb/serial.h>
+#include "usb-serial.h"
#include "pl2303.h"
/*
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
-static void port_free(struct usb_serial_port *port);
-
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
port = serial->port[i];
if (!port)
continue;
- port_free(port);
+ usb_kill_urb(port->read_urb);
+ usb_free_urb(port->read_urb);
+ usb_kill_urb(port->write_urb);
+ usb_free_urb(port->write_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+ usb_free_urb(port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_out_urb);
+ usb_free_urb(port->interrupt_out_urb);
+ kfree(port->bulk_in_buffer);
+ kfree(port->bulk_out_buffer);
+ kfree(port->interrupt_in_buffer);
+ kfree(port->interrupt_out_buffer);
}
}
kfree (serial);
}
-void usb_serial_put(struct usb_serial *serial)
-{
- kref_put(&serial->kref, destroy_serial);
-}
-
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
portNumber = tty->index - serial->minor;
port = serial->port[portNumber];
- if (!port) {
- retval = -ENODEV;
- goto bailout_kref_put;
- }
+ if (!port)
+ return -ENODEV;
- if (mutex_lock_interruptible(&port->mutex)) {
- retval = -ERESTARTSYS;
- goto bailout_kref_put;
- }
+ if (down_interruptible(&port->sem))
+ return -ERESTARTSYS;
++port->open_count;
- /* set up our port structure making the tty driver
- * remember our port object, and us it */
- tty->driver_data = port;
- port->tty = tty;
-
if (port->open_count == 1) {
+ /* set up our port structure making the tty driver
+ * remember our port object, and us it */
+ tty->driver_data = port;
+ port->tty = tty;
+
/* lock this module before we call it
* this may fail, which means we must bail out,
* safe because we are called with BKL held */
if (!try_module_get(serial->type->driver.owner)) {
retval = -ENODEV;
- goto bailout_mutex_unlock;
+ goto bailout_kref_put;
}
/* only call the device specific open if this
goto bailout_module_put;
}
- mutex_unlock(&port->mutex);
+ up(&port->sem);
return 0;
bailout_module_put:
module_put(serial->type->driver.owner);
-bailout_mutex_unlock:
- port->open_count = 0;
- tty->driver_data = NULL;
- port->tty = NULL;
- mutex_unlock(&port->mutex);
bailout_kref_put:
- usb_serial_put(serial);
+ kref_put(&serial->kref, destroy_serial);
+ port->open_count = 0;
+ up(&port->sem);
return retval;
}
dbg("%s - port %d", __FUNCTION__, port->number);
- mutex_lock(&port->mutex);
+ down(&port->sem);
if (port->open_count == 0) {
- mutex_unlock(&port->mutex);
+ up(&port->sem);
return;
}
module_put(port->serial->type->driver.owner);
}
- mutex_unlock(&port->mutex);
- usb_serial_put(port->serial);
+ up(&port->sem);
+ kref_put(&port->serial->kref, destroy_serial);
}
static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
struct usb_serial_port *port = tty->driver_data;
int retval = -EINVAL;
- if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
+ if (!port)
goto exit;
dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
+ int retval = -EINVAL;
if (!port)
goto exit;
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
+ int retval = -EINVAL;
if (!port)
goto exit;
length += sprintf (page+length, " path:%s", tmp);
length += sprintf (page+length, "\n");
- if ((length + begin) > (off + count)) {
- usb_serial_put(serial);
+ if ((length + begin) > (off + count))
goto done;
- }
if ((length + begin) < off) {
begin += length;
length = 0;
}
- usb_serial_put(serial);
+ kref_put(&serial->kref, destroy_serial);
}
*eof = 1;
done:
struct usb_serial_port *port = tty->driver_data;
if (!port)
- return -ENODEV;
+ goto exit;
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
- return -ENODEV;
+ goto exit;
}
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file);
+exit:
return -EINVAL;
}
struct usb_serial_port *port = tty->driver_data;
if (!port)
- return -ENODEV;
+ goto exit;
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->open_count) {
dbg("%s - port not open", __FUNCTION__);
- return -ENODEV;
+ goto exit;
}
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear);
+exit:
return -EINVAL;
}
-/*
- * We would be calling tty_wakeup here, but unfortunately some line
- * disciplines have an annoying habit of calling tty->write from
- * the write wakeup callback (e.g. n_hdlc.c).
- */
-void usb_serial_port_softint(struct usb_serial_port *port)
-{
- schedule_work(&port->work);
-}
-
-static void usb_serial_port_work(void *private)
+void usb_serial_port_softint(void *private)
{
struct usb_serial_port *port = private;
struct tty_struct *tty;
struct usb_serial_port *port = to_usb_serial_port(dev);
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
- port_free(port);
-}
-
-static void port_free(struct usb_serial_port *port)
-{
usb_kill_urb(port->read_urb);
usb_free_urb(port->read_urb);
usb_kill_urb(port->write_urb);
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port->interrupt_out_buffer);
- flush_scheduled_work(); /* port->work */
kfree(port);
}
{
struct usb_serial *serial;
- serial = kzalloc(sizeof(*serial), GFP_KERNEL);
+ 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 = driver;
serial->interface = interface;
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 = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
+ 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;
spin_lock_init(&port->lock);
- mutex_init(&port->mutex);
- INIT_WORK(&port->work, usb_serial_port_work, port);
+ sema_init(&port->sem, 1);
+ INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
struct device *dev = &interface->dev;
struct usb_serial_port *port;
- usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__);
usb_set_intfdata (interface, NULL);
}
/* let the last holder of this object
* cause it to be cleaned up */
- usb_serial_put(serial);
+ kref_put(&serial->kref, destroy_serial);
}
dev_info(dev, "device disconnected\n");
}
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_DYNAMIC_DEV;
+ 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);