summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <greg@kroah.com>2002-06-13 23:31:35 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2002-06-13 23:31:35 -0700
commit8274ff48a6528fc486db8b80664c2546dcb4e5cd (patch)
tree4fa9b0d18485770222daad6f4994ba1f88df0fdd /drivers/usb
parent15d557427f1a62bd45a180c070896ce3257a2945 (diff)
USB: usb-serial api changes
- added calc_num_ports() callback so that driver can override the fixed num_ports value after querying the device. - split startup() callback into probe() and attach() in anticipation of the driverfs api changes - probe() is called before the usb_serial structure is set up, and can be used to download firmware to a device, and other early initialization. - attach() is called after the usb_serial structure is completely setup, allowing the device to create private structures, and have full access to the device.
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/serial/usb-serial.h22
-rw-r--r--drivers/usb/serial/usbserial.c110
2 files changed, 107 insertions, 25 deletions
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index f072a3f5da08..9ce636644ded 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -130,9 +130,20 @@ struct usb_serial {
* @num_bulk_in: the number of bulk in endpoints this device will have.
* @num_bulk_out: the number of bulk out endpoints this device will have.
* @num_ports: the number of different ports this device will have.
- * @startup: pointer to the driver's startup function. This will be called
- * when the driver is inserted into the system. Return 0 to continue
- * on with the initialization sequence. Anything else will abort it.
+ * @calc_num_ports: pointer to a function to determine how many ports this
+ * device has dynamically. It will be called after the probe()
+ * callback is called, but before attach()
+ * @probe: pointer to the driver's probe function.
+ * This will be called when the device is inserted into the system,
+ * but before the device has been fully initialized by the usb_serial
+ * subsystem. Use this function to download any firmware to the device,
+ * or any other early initialization that might be needed.
+ * Return 0 to continue on with the initialization sequence. Anything
+ * else will abort it.
+ * @attach: pointer to the driver's attach function.
+ * This will be called when the struct usb_serial structure is fully set
+ * set up. Do any local initialization of the device, or any private
+ * memory structure allocation at this point in time.
* @shutdown: pointer to the driver's shutdown function. This will be
* called when the device is removed from the system.
*
@@ -153,7 +164,10 @@ struct usb_serial_device_type {
struct list_head driver_list;
- int (*startup) (struct usb_serial *serial);
+ int (*probe) (struct usb_serial *serial);
+ int (*attach) (struct usb_serial *serial);
+ int (*calc_num_ports) (struct usb_serial *serial);
+
void (*shutdown) (struct usb_serial *serial);
/* serial function calls */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 25a6022910b5..2e556292db6a 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -433,9 +433,8 @@ static struct usb_serial *get_serial_by_minor (unsigned int minor)
return serial_table[minor];
}
-static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
+static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_ports, unsigned int *minor)
{
- struct usb_serial *serial = NULL;
unsigned int i, j;
int good_spot;
@@ -453,11 +452,14 @@ static struct usb_serial *get_free_serial (int num_ports, unsigned int *minor)
if (good_spot == 0)
continue;
- if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) {
- err(__FUNCTION__ " - Out of memory");
- return NULL;
+ if (!serial) {
+ serial = kmalloc(sizeof(*serial), GFP_KERNEL);
+ if (!serial) {
+ err(__FUNCTION__ " - Out of memory");
+ return NULL;
+ }
+ memset(serial, 0, sizeof(*serial));
}
- memset(serial, 0, sizeof(struct usb_serial));
serial->magic = USB_SERIAL_MAGIC;
serial_table[i] = serial;
*minor = i;
@@ -1140,6 +1142,27 @@ static void port_softint(void *private)
wake_up_interruptible(&tty->write_wait);
}
+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) {
+ err ("%s - out of memory", __FUNCTION__);
+ return NULL;
+ }
+ memset (serial, 0, sizeof(*serial));
+ serial->dev = dev;
+ serial->type = type;
+ serial->interface = interface;
+ serial->vendor = dev->descriptor.idVendor;
+ serial->product = dev->descriptor.idProduct;
+
+ return serial;
+}
+
static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
@@ -1161,7 +1184,7 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
int num_interrupt_in = 0;
int num_bulk_in = 0;
int num_bulk_out = 0;
- int num_ports;
+ int num_ports = 0;
int max_endpoints;
const struct usb_device_id *id_pattern = NULL;
@@ -1184,6 +1207,27 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
return(NULL);
}
+ /* if this device type has a probe function, call it */
+ if (type->probe) {
+ serial = create_serial (dev, interface, type);
+ if (!serial) {
+ err ("%s - out of memory", __FUNCTION__);
+ return NULL;
+ }
+
+ if (type->owner)
+ __MOD_INC_USE_COUNT(type->owner);
+ retval = type->probe (serial);
+ if (type->owner)
+ __MOD_DEC_USE_COUNT(type->owner);
+
+ if (retval < 0) {
+ dbg ("sub driver rejected device");
+ kfree (serial);
+ return NULL;
+ }
+ }
+
/* descriptor matches, let's find the endpoints needed */
/* check out the endpoints */
iface_desc = &interface->altsetting[0];
@@ -1251,11 +1295,30 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
err("Generic device with no bulk out, not allowed.");
return NULL;
}
- } else
+ }
#endif
- num_ports = type->num_ports;
+ if (!num_ports) {
+ /* if this device type has a calc_num_ports function, call it */
+ if (type->calc_num_ports) {
+ if (!serial) {
+ serial = create_serial (dev, interface, type);
+ if (!serial) {
+ err ("%s - out of memory", __FUNCTION__);
+ return NULL;
+ }
+ }
- serial = get_free_serial (num_ports, &minor);
+ if (type->owner)
+ __MOD_INC_USE_COUNT(type->owner);
+ num_ports = type->calc_num_ports (serial);
+ if (type->owner)
+ __MOD_DEC_USE_COUNT(type->owner);
+ }
+ if (!num_ports)
+ num_ports = type->num_ports;
+ }
+
+ serial = get_free_serial (serial, num_ports, &minor);
if (serial == NULL) {
err("No more free serial devices");
return NULL;
@@ -1272,17 +1335,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
serial->vendor = dev->descriptor.idVendor;
serial->product = dev->descriptor.idProduct;
- /* if this device type has a startup function, call it */
- if (type->startup) {
- if (type->owner)
- __MOD_INC_USE_COUNT(type->owner);
- retval = type->startup (serial);
- if (type->owner)
- __MOD_DEC_USE_COUNT(type->owner);
- if (retval)
- goto probe_error;
- }
-
/* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) {
endpoint = bulk_in_endpoint[i];
@@ -1374,6 +1426,22 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
init_MUTEX (&port->sem);
}
+ /* if this device type has an attach function, call it */
+ if (type->attach) {
+ if (type->owner)
+ __MOD_INC_USE_COUNT(type->owner);
+ retval = type->attach (serial);
+ if (type->owner)
+ __MOD_DEC_USE_COUNT(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 */
+ return serial;
+ }
+ }
+
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
for (i = 0; i < serial->num_ports; ++i) {
tty_register_devfs (&serial_tty_driver, 0, serial->port[i].number);