|
@@ -56,89 +56,115 @@ MODULE_DEVICE_TABLE(usb, id_table);
|
|
|
/* Input parameter constants. */
|
|
|
static bool debug;
|
|
|
|
|
|
-/* Function prototypes. */
|
|
|
-static void metrousb_cleanup(struct usb_serial_port *port);
|
|
|
-static void metrousb_close(struct usb_serial_port *port);
|
|
|
-static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port);
|
|
|
-static void metrousb_read_int_callback(struct urb *urb);
|
|
|
-static void metrousb_shutdown(struct usb_serial *serial);
|
|
|
-static int metrousb_startup(struct usb_serial *serial);
|
|
|
-static void metrousb_throttle(struct tty_struct *tty);
|
|
|
-static int metrousb_tiocmget(struct tty_struct *tty);
|
|
|
-static int metrousb_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear);
|
|
|
-static void metrousb_unthrottle(struct tty_struct *tty);
|
|
|
-
|
|
|
-/* Driver structure. */
|
|
|
-static struct usb_driver metrousb_driver = {
|
|
|
- .name = "metro-usb",
|
|
|
- .probe = usb_serial_probe,
|
|
|
- .disconnect = usb_serial_disconnect,
|
|
|
- .id_table = id_table
|
|
|
-};
|
|
|
-
|
|
|
-/* Device structure. */
|
|
|
-static struct usb_serial_driver metrousb_device = {
|
|
|
- .driver = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .name = "metro-usb",
|
|
|
- },
|
|
|
- .description = "Metrologic USB to serial converter.",
|
|
|
- .id_table = id_table,
|
|
|
- .num_ports = 1,
|
|
|
- .open = metrousb_open,
|
|
|
- .close = metrousb_close,
|
|
|
- .read_int_callback = metrousb_read_int_callback,
|
|
|
- .attach = metrousb_startup,
|
|
|
- .release = metrousb_shutdown,
|
|
|
- .throttle = metrousb_throttle,
|
|
|
- .unthrottle = metrousb_unthrottle,
|
|
|
- .tiocmget = metrousb_tiocmget,
|
|
|
- .tiocmset = metrousb_tiocmset,
|
|
|
-};
|
|
|
-
|
|
|
-static struct usb_serial_driver * const serial_drivers[] = {
|
|
|
- &metrousb_device,
|
|
|
- NULL,
|
|
|
-};
|
|
|
-
|
|
|
/* ----------------------------------------------------------------------------------------------
|
|
|
Description:
|
|
|
- Clean up any urbs and port information.
|
|
|
+ Read the port from the read interrupt.
|
|
|
|
|
|
Input:
|
|
|
- struct usb_serial_port *: pointer to a usb_serial_port structure.
|
|
|
+ struct urb *: urb structure to get data.
|
|
|
+ struct pt_regs *: pt_regs structure.
|
|
|
|
|
|
Output:
|
|
|
- int: Returns true (0) if successful, false otherwise.
|
|
|
+ None:
|
|
|
*/
|
|
|
-static void metrousb_cleanup(struct usb_serial_port *port)
|
|
|
+static void metrousb_read_int_callback(struct urb *urb)
|
|
|
{
|
|
|
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
|
|
|
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
|
|
|
+ struct tty_struct *tty;
|
|
|
+ unsigned char *data = urb->transfer_buffer;
|
|
|
+ int throttled = 0;
|
|
|
+ int result = 0;
|
|
|
+ unsigned long flags = 0;
|
|
|
+
|
|
|
dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number);
|
|
|
|
|
|
- if (port->serial->dev) {
|
|
|
- /* Shutdown any interrupt in urbs. */
|
|
|
- if (port->interrupt_in_urb) {
|
|
|
- usb_unlink_urb(port->interrupt_in_urb);
|
|
|
- usb_kill_urb(port->interrupt_in_urb);
|
|
|
+ switch (urb->status) {
|
|
|
+ case 0:
|
|
|
+ /* Success status, read from the port. */
|
|
|
+ break;
|
|
|
+ case -ECONNRESET:
|
|
|
+ case -ENOENT:
|
|
|
+ case -ESHUTDOWN:
|
|
|
+ /* urb has been terminated. */
|
|
|
+ dbg("METRO-USB - %s - urb shutting down, port number=%d, error code=%d",
|
|
|
+ __FUNCTION__, port->number, result);
|
|
|
+ return;
|
|
|
+ default:
|
|
|
+ dbg("METRO-USB - %s - non-zero urb received, port number=%d, error code=%d",
|
|
|
+ __FUNCTION__, port->number, result);
|
|
|
+ goto exit;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* Set the data read from the usb port into the serial port buffer. */
|
|
|
+ tty = tty_port_tty_get(&port->port);
|
|
|
+ if (!tty) {
|
|
|
+ dbg("%s - bad tty pointer - exiting", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tty && urb->actual_length) {
|
|
|
+ /* Loop through the data copying each byte to the tty layer. */
|
|
|
+ tty_insert_flip_string(tty, data, urb->actual_length);
|
|
|
+
|
|
|
+ /* Force the data to the tty layer. */
|
|
|
+ tty_flip_buffer_push(tty);
|
|
|
+ }
|
|
|
+ tty_kref_put(tty);
|
|
|
+
|
|
|
+ /* Set any port variables. */
|
|
|
+ spin_lock_irqsave(&metro_priv->lock, flags);
|
|
|
+ throttled = metro_priv->throttled;
|
|
|
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
|
|
|
+
|
|
|
+ /* Continue trying to read if set. */
|
|
|
+ if (!throttled) {
|
|
|
+ usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
|
|
|
+ usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
|
|
|
+ port->interrupt_in_urb->transfer_buffer,
|
|
|
+ port->interrupt_in_urb->transfer_buffer_length,
|
|
|
+ metrousb_read_int_callback, port, 1);
|
|
|
+
|
|
|
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
|
|
+
|
|
|
+ if (result) {
|
|
|
+ dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d",
|
|
|
+ __FUNCTION__, port->number, result);
|
|
|
}
|
|
|
}
|
|
|
+ return;
|
|
|
+
|
|
|
+exit:
|
|
|
+ /* Try to resubmit the urb. */
|
|
|
+ result = usb_submit_urb(urb, GFP_ATOMIC);
|
|
|
+ if (result) {
|
|
|
+ dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d",
|
|
|
+ __FUNCTION__, port->number, result);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------------------------
|
|
|
Description:
|
|
|
- Close the open serial port. Cleanup any open serial port information.
|
|
|
+ Clean up any urbs and port information.
|
|
|
|
|
|
Input:
|
|
|
struct usb_serial_port *: pointer to a usb_serial_port structure.
|
|
|
- struct file *: pointer to a file structure.
|
|
|
|
|
|
Output:
|
|
|
int: Returns true (0) if successful, false otherwise.
|
|
|
*/
|
|
|
-static void metrousb_close(struct usb_serial_port *port)
|
|
|
+static void metrousb_cleanup(struct usb_serial_port *port)
|
|
|
{
|
|
|
dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number);
|
|
|
- metrousb_cleanup(port);
|
|
|
+
|
|
|
+ if (port->serial->dev) {
|
|
|
+ /* Shutdown any interrupt in urbs. */
|
|
|
+ if (port->interrupt_in_urb) {
|
|
|
+ usb_unlink_urb(port->interrupt_in_urb);
|
|
|
+ usb_kill_urb(port->interrupt_in_urb);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------------------------------
|
|
@@ -203,94 +229,6 @@ exit:
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-/* ----------------------------------------------------------------------------------------------
|
|
|
- Description:
|
|
|
- Read the port from the read interrupt.
|
|
|
-
|
|
|
- Input:
|
|
|
- struct urb *: urb structure to get data.
|
|
|
- struct pt_regs *: pt_regs structure.
|
|
|
-
|
|
|
- Output:
|
|
|
- None:
|
|
|
-*/
|
|
|
-static void metrousb_read_int_callback(struct urb *urb)
|
|
|
-{
|
|
|
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
|
|
|
- struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
|
|
|
- struct tty_struct *tty;
|
|
|
- unsigned char *data = urb->transfer_buffer;
|
|
|
- int throttled = 0;
|
|
|
- int result = 0;
|
|
|
- unsigned long flags = 0;
|
|
|
-
|
|
|
- dbg("METRO-USB - %s - port number=%d", __FUNCTION__, port->number);
|
|
|
-
|
|
|
- switch (urb->status) {
|
|
|
- case 0:
|
|
|
- /* Success status, read from the port. */
|
|
|
- break;
|
|
|
- case -ECONNRESET:
|
|
|
- case -ENOENT:
|
|
|
- case -ESHUTDOWN:
|
|
|
- /* urb has been terminated. */
|
|
|
- dbg("METRO-USB - %s - urb shutting down, port number=%d, error code=%d",
|
|
|
- __FUNCTION__, port->number, result);
|
|
|
- return;
|
|
|
- default:
|
|
|
- dbg("METRO-USB - %s - non-zero urb received, port number=%d, error code=%d",
|
|
|
- __FUNCTION__, port->number, result);
|
|
|
- goto exit;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /* Set the data read from the usb port into the serial port buffer. */
|
|
|
- tty = tty_port_tty_get(&port->port);
|
|
|
- if (!tty) {
|
|
|
- dbg("%s - bad tty pointer - exiting", __func__);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (tty && urb->actual_length) {
|
|
|
- /* Loop through the data copying each byte to the tty layer. */
|
|
|
- tty_insert_flip_string(tty, data, urb->actual_length);
|
|
|
-
|
|
|
- /* Force the data to the tty layer. */
|
|
|
- tty_flip_buffer_push(tty);
|
|
|
- }
|
|
|
- tty_kref_put(tty);
|
|
|
-
|
|
|
- /* Set any port variables. */
|
|
|
- spin_lock_irqsave(&metro_priv->lock, flags);
|
|
|
- throttled = metro_priv->throttled;
|
|
|
- spin_unlock_irqrestore(&metro_priv->lock, flags);
|
|
|
-
|
|
|
- /* Continue trying to read if set. */
|
|
|
- if (!throttled) {
|
|
|
- usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
|
|
|
- usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
|
|
|
- port->interrupt_in_urb->transfer_buffer,
|
|
|
- port->interrupt_in_urb->transfer_buffer_length,
|
|
|
- metrousb_read_int_callback, port, 1);
|
|
|
-
|
|
|
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
|
|
-
|
|
|
- if (result) {
|
|
|
- dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d",
|
|
|
- __FUNCTION__, port->number, result);
|
|
|
- }
|
|
|
- }
|
|
|
- return;
|
|
|
-
|
|
|
-exit:
|
|
|
- /* Try to resubmit the urb. */
|
|
|
- result = usb_submit_urb(urb, GFP_ATOMIC);
|
|
|
- if (result) {
|
|
|
- dbg("METRO-USB - %s - failed submitting interrupt in urb for port number=%d, error code=%d",
|
|
|
- __FUNCTION__, port->number, result);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/* ----------------------------------------------------------------------------------------------
|
|
|
Description:
|
|
|
Set the modem control state for the entered serial port.
|
|
@@ -522,6 +460,39 @@ static void metrousb_unthrottle(struct tty_struct *tty)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* Driver structure. */
|
|
|
+static struct usb_driver metrousb_driver = {
|
|
|
+ .name = "metro-usb",
|
|
|
+ .probe = usb_serial_probe,
|
|
|
+ .disconnect = usb_serial_disconnect,
|
|
|
+ .id_table = id_table
|
|
|
+};
|
|
|
+
|
|
|
+/* Device structure. */
|
|
|
+static struct usb_serial_driver metrousb_device = {
|
|
|
+ .driver = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .name = "metro-usb",
|
|
|
+ },
|
|
|
+ .description = "Metrologic USB to serial converter.",
|
|
|
+ .id_table = id_table,
|
|
|
+ .num_ports = 1,
|
|
|
+ .open = metrousb_open,
|
|
|
+ .close = metrousb_cleanup,
|
|
|
+ .read_int_callback = metrousb_read_int_callback,
|
|
|
+ .attach = metrousb_startup,
|
|
|
+ .release = metrousb_shutdown,
|
|
|
+ .throttle = metrousb_throttle,
|
|
|
+ .unthrottle = metrousb_unthrottle,
|
|
|
+ .tiocmget = metrousb_tiocmget,
|
|
|
+ .tiocmset = metrousb_tiocmset,
|
|
|
+};
|
|
|
+
|
|
|
+static struct usb_serial_driver * const serial_drivers[] = {
|
|
|
+ &metrousb_device,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
module_usb_serial_driver(metrousb_driver, serial_drivers);
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|