* [PATCH 1/3] hso modem signals patch fix
@ 2008-12-08 10:37 Denis Joseph Barrow
[not found] ` <493CF8F5.30007-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2008-12-08 11:34 ` Alan Cox
0 siblings, 2 replies; 3+ messages in thread
From: Denis Joseph Barrow @ 2008-12-08 10:37 UTC (permalink / raw)
To: Linux netdev Mailing list, Linux USB kernel mailing list
[-- Attachment #1: Type: text/plain, Size: 13620 bytes --]
Hi,
This patch is a respin of a previously sent patch,
I inherited a bug from previous code on detecting the modem
port which causes a crash on opening control ports doing
because the check
if (port & HSO_PORT_MODEM)
should be
if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
& a urb gets submitted to a non existent endpoint.
Makes TIOCM ioctls for Data Carrier Detect & related functions
work like /drivers/serial/serial-core.c potentially needed
for pppd & similar user programs.
Signed-off-by: Denis Joseph Barrow <D.Barow-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
---
Index: linux-2.6.28-rc6.patches/drivers/net/usb/hso.c
===================================================================
--- linux-2.6.28-rc6.patches.orig/drivers/net/usb/hso.c 2008-11-24 17:07:07.000000000 +0100
+++ linux-2.6.28-rc6.patches/drivers/net/usb/hso.c 2008-12-08 11:18:55.000000000 +0100
@@ -39,8 +39,11 @@
* port is opened, as this have a huge impact on the network port
* throughput.
*
- * Interface 2: Standard modem interface - circuit switched interface, should
- * not be used.
+ * Interface 2: Standard modem interface - circuit switched interface, this
+ * can be used to make a standard ppp connection however it
+ * should not be used in conjunction with the IP network interface
+ * enabled for USB performance reasons i.e. if using this set
+ * ideally disable_net=1.
*
*****************************************************************************/
@@ -63,6 +66,8 @@
#include <linux/usb/cdc.h>
#include <net/arp.h>
#include <asm/byteorder.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
#define DRIVER_VERSION "1.2"
@@ -182,6 +187,41 @@
RX_PENDING
};
+#define BM_REQUEST_TYPE (0xa1)
+#define B_NOTIFICATION (0x20)
+#define W_VALUE (0x0)
+#define W_INDEX (0x2)
+#define W_LENGTH (0x2)
+
+#define B_OVERRUN (0x1<<6)
+#define B_PARITY (0x1<<5)
+#define B_FRAMING (0x1<<4)
+#define B_RING_SIGNAL (0x1<<3)
+#define B_BREAK (0x1<<2)
+#define B_TX_CARRIER (0x1<<1)
+#define B_RX_CARRIER (0x1<<0)
+
+struct hso_serial_state_notification {
+ u8 bmRequestType;
+ u8 bNotification;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+ u16 UART_state_bitmap;
+} __attribute__((packed));
+
+struct hso_tiocmget {
+ struct mutex mutex;
+ wait_queue_head_t waitq;
+ int intr_completed;
+ struct usb_endpoint_descriptor *endp;
+ struct urb *urb;
+ struct hso_serial_state_notification serial_state_notification;
+ u16 prev_UART_state_bitmap;
+ struct uart_icount icount;
+};
+
+
struct hso_serial {
struct hso_device *parent;
int magic;
@@ -219,6 +259,7 @@
spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial);
+ struct hso_tiocmget *tiocmget;
/* Hacks required to get flow control
* working on the serial receive buffers
* so as not to drop characters on the floor.
@@ -310,7 +351,7 @@
static void async_put_intf(struct work_struct *data);
static int hso_put_activity(struct hso_device *hso_dev);
static int hso_get_activity(struct hso_device *hso_dev);
-
+static void tiocmget_intr_callback(struct urb *urb);
/*****************************************************************************/
/* Helping functions */
/*****************************************************************************/
@@ -1460,25 +1501,217 @@
return chars;
}
+int tiocmget_submit_urb(struct hso_serial *serial,
+ struct hso_tiocmget *tiocmget,
+ struct usb_device *usb)
+{
+ int result;
+
+ if (serial->parent->usb_gone)
+ return -ENODEV;
+ usb_fill_int_urb(tiocmget->urb, usb,
+ usb_rcvintpipe(usb,
+ tiocmget->endp->
+ bEndpointAddress & 0x7F),
+ &tiocmget->serial_state_notification,
+ sizeof(struct hso_serial_state_notification),
+ tiocmget_intr_callback, serial,
+ tiocmget->endp->bInterval);
+ result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
+ if (result) {
+ dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
+ result);
+ }
+ return result;
+
+}
+
+static void tiocmget_intr_callback(struct urb *urb)
+{
+ struct hso_serial *serial = urb->context;
+ struct hso_tiocmget *tiocmget;
+ int status = urb->status;
+ u16 UART_state_bitmap, prev_UART_state_bitmap;
+ struct uart_icount *icount;
+ struct hso_serial_state_notification *serial_state_notification;
+ struct usb_device *usb;
+
+ /* Sanity checks */
+ if (!serial)
+ return;
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+ tiocmget = serial->tiocmget;
+ if (!tiocmget)
+ return;
+ usb = serial->parent->usb;
+ serial_state_notification = &tiocmget->serial_state_notification;
+ if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
+ serial_state_notification->bNotification != B_NOTIFICATION ||
+ le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
+ le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
+ le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
+ dev_warn(&usb->dev,
+ "hso received invalid serial state notification\n");
+ DUMP(serial_state_notification,
+ sizeof(hso_serial_state_notifation))
+ } else {
+
+ UART_state_bitmap = le16_to_cpu(serial_state_notification->
+ UART_state_bitmap);
+ prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
+ icount = &tiocmget->icount;
+ spin_lock(&serial->serial_lock);
+ if ((UART_state_bitmap & B_OVERRUN) !=
+ (prev_UART_state_bitmap & B_OVERRUN))
+ icount->parity++;
+ if ((UART_state_bitmap & B_PARITY) !=
+ (prev_UART_state_bitmap & B_PARITY))
+ icount->parity++;
+ if ((UART_state_bitmap & B_FRAMING) !=
+ (prev_UART_state_bitmap & B_FRAMING))
+ icount->frame++;
+ if ((UART_state_bitmap & B_RING_SIGNAL) &&
+ !(prev_UART_state_bitmap & B_RING_SIGNAL))
+ icount->rng++;
+ if ((UART_state_bitmap & B_BREAK) !=
+ (prev_UART_state_bitmap & B_BREAK))
+ icount->brk++;
+ if ((UART_state_bitmap & B_TX_CARRIER) !=
+ (prev_UART_state_bitmap & B_TX_CARRIER))
+ icount->dsr++;
+ if ((UART_state_bitmap & B_RX_CARRIER) !=
+ (prev_UART_state_bitmap & B_RX_CARRIER))
+ icount->dcd++;
+ tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
+ spin_unlock(&serial->serial_lock);
+ tiocmget->intr_completed = 1;
+ wake_up_interruptible(&tiocmget->waitq);
+ }
+ memset(serial_state_notification, 0,
+ sizeof(struct hso_serial_state_notification));
+ tiocmget_submit_urb(serial,
+ tiocmget,
+ serial->parent->usb);
+}
+
+/*
+ * next few functions largely stolen from drivers/serial/serial_core.c
+ */
+/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+static int
+hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct uart_icount cprev, cnow;
+ struct hso_tiocmget *tiocmget;
+ int ret;
+
+ tiocmget = serial->tiocmget;
+ if (!tiocmget)
+ return -ENOENT;
+ /*
+ * note the counters on entry
+ */
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+ add_wait_queue(&tiocmget->waitq, &wait);
+ for (;;) {
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
+ ret = 0;
+ break;
+ }
+ schedule();
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ cprev = cnow;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&tiocmget->waitq, &wait);
+
+ return ret;
+}
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+static int hso_get_count(struct hso_serial *serial,
+ struct serial_icounter_struct __user *icnt)
+{
+ struct serial_icounter_struct icount;
+ struct uart_icount cnow;
+ struct hso_tiocmget *tiocmget = serial->tiocmget;
+
+ if (!tiocmget)
+ return -ENOENT;
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
+}
+
static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
{
- unsigned int value;
+ int retval;
struct hso_serial *serial = get_serial_by_tty(tty);
- unsigned long flags;
+ struct hso_tiocmget *tiocmget;
+ u16 UART_state_bitmap;
/* sanity check */
if (!serial) {
D1("no tty structures");
return -EINVAL;
}
-
- spin_lock_irqsave(&serial->serial_lock, flags);
- value = ((serial->rts_state) ? TIOCM_RTS : 0) |
+ spin_lock_irq(&serial->serial_lock);
+ retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
((serial->dtr_state) ? TIOCM_DTR : 0);
- spin_unlock_irqrestore(&serial->serial_lock, flags);
+ tiocmget = serial->tiocmget;
+ if (tiocmget) {
- return value;
+ UART_state_bitmap = le16_to_cpu(
+ tiocmget->prev_UART_state_bitmap);
+ if (UART_state_bitmap & B_RING_SIGNAL)
+ retval |= TIOCM_RNG;
+ if (UART_state_bitmap & B_RX_CARRIER)
+ retval |= TIOCM_CD;
+ if (UART_state_bitmap & B_TX_CARRIER)
+ retval |= TIOCM_DSR;
+ }
+ spin_unlock_irq(&serial->serial_lock);
+ return retval;
}
static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@@ -1520,6 +1753,32 @@
USB_CTRL_SET_TIMEOUT);
}
+static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ void __user *uarg = (void __user *)arg;
+ int ret = 0;
+ D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
+
+ if (!serial)
+ return -ENODEV;
+ switch (cmd) {
+ case TIOCMIWAIT:
+ ret = hso_wait_modem_status(serial, arg);
+ break;
+
+ case TIOCGICOUNT:
+ ret = hso_get_count(serial, uarg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ return ret;
+}
+
+
/* starts a transmit */
static void hso_kick_transmit(struct hso_serial *serial)
{
@@ -1982,7 +2241,10 @@
serial->shared_int->use_count++;
mutex_unlock(&serial->shared_int->shared_int_lock);
}
-
+ if (serial->tiocmget)
+ tiocmget_submit_urb(serial,
+ serial->tiocmget,
+ serial->parent->usb);
return result;
}
@@ -1990,6 +2252,7 @@
{
int i;
struct hso_serial *serial = dev2ser(hso_dev);
+ struct hso_tiocmget *tiocmget;
if (!serial)
return -ENODEV;
@@ -2018,6 +2281,11 @@
}
mutex_unlock(&serial->shared_int->shared_int_lock);
}
+ tiocmget = serial->tiocmget;
+ if (tiocmget) {
+ wake_up_interruptible(&tiocmget->waitq);
+ usb_kill_urb(tiocmget->urb);
+ }
return 0;
}
@@ -2368,6 +2636,20 @@
return NULL;
}
+static void hso_free_tiomget(struct hso_serial *serial)
+{
+ struct hso_tiocmget *tiocmget = serial->tiocmget;
+ if (tiocmget) {
+ kfree(tiocmget);
+ if (tiocmget->urb) {
+ usb_free_urb(tiocmget->urb);
+ tiocmget->urb = NULL;
+ }
+ serial->tiocmget = NULL;
+
+ }
+}
+
/* Frees an AT channel ( goes for both mux and non-mux ) */
static void hso_free_serial_device(struct hso_device *hso_dev)
{
@@ -2386,6 +2668,7 @@
else
mutex_unlock(&serial->shared_int->shared_int_lock);
}
+ hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
}
@@ -2397,6 +2680,7 @@
struct hso_device *hso_dev;
struct hso_serial *serial;
int num_urbs;
+ struct hso_tiocmget *tiocmget;
hso_dev = hso_create_device(interface, port);
if (!hso_dev)
@@ -2408,9 +2692,27 @@
serial->parent = hso_dev;
hso_dev->port_data.dev_serial = serial;
-
- if (port & HSO_PORT_MODEM)
+ if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
num_urbs = 2;
+ serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
+ GFP_KERNEL);
+ /* it isn't going to break our heart if serial->tiocmget
+ * allocation fails don't bother checking this.
+ */
+ if (serial->tiocmget) {
+ tiocmget = serial->tiocmget;
+ tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (tiocmget->urb) {
+ mutex_init(&tiocmget->mutex);
+ init_waitqueue_head(&tiocmget->waitq);
+ tiocmget->endp = hso_get_ep(
+ interface,
+ USB_ENDPOINT_XFER_INT,
+ USB_DIR_IN);
+ } else
+ hso_free_tiomget(serial);
+ }
+ }
else
num_urbs = 1;
@@ -2446,6 +2748,7 @@
exit2:
hso_serial_common_free(serial);
exit:
+ hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
return NULL;
@@ -2958,6 +3261,7 @@
.close = hso_serial_close,
.write = hso_serial_write,
.write_room = hso_serial_write_room,
+ .ioctl = hso_serial_ioctl,
.set_termios = hso_serial_set_termios,
.chars_in_buffer = hso_serial_chars_in_buffer,
.tiocmget = hso_serial_tiocmget,
--
best regards,
D.J. Barrow
[-- Attachment #2: hso_modem_signals.patch --]
[-- Type: text/x-diff, Size: 13262 bytes --]
Makes TIOCM ioctls for Data Carrier Detect & related functions
work like /drivers/serial/serial-core.c potentially needed
for pppd & similar user programs.
Signed-off-by: Denis Joseph Barrow <D.Barow-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
---
Index: linux-2.6.28-rc6.patches/drivers/net/usb/hso.c
===================================================================
--- linux-2.6.28-rc6.patches.orig/drivers/net/usb/hso.c 2008-11-24 17:07:07.000000000 +0100
+++ linux-2.6.28-rc6.patches/drivers/net/usb/hso.c 2008-12-08 11:18:55.000000000 +0100
@@ -39,8 +39,11 @@
* port is opened, as this have a huge impact on the network port
* throughput.
*
- * Interface 2: Standard modem interface - circuit switched interface, should
- * not be used.
+ * Interface 2: Standard modem interface - circuit switched interface, this
+ * can be used to make a standard ppp connection however it
+ * should not be used in conjunction with the IP network interface
+ * enabled for USB performance reasons i.e. if using this set
+ * ideally disable_net=1.
*
*****************************************************************************/
@@ -63,6 +66,8 @@
#include <linux/usb/cdc.h>
#include <net/arp.h>
#include <asm/byteorder.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
#define DRIVER_VERSION "1.2"
@@ -182,6 +187,41 @@
RX_PENDING
};
+#define BM_REQUEST_TYPE (0xa1)
+#define B_NOTIFICATION (0x20)
+#define W_VALUE (0x0)
+#define W_INDEX (0x2)
+#define W_LENGTH (0x2)
+
+#define B_OVERRUN (0x1<<6)
+#define B_PARITY (0x1<<5)
+#define B_FRAMING (0x1<<4)
+#define B_RING_SIGNAL (0x1<<3)
+#define B_BREAK (0x1<<2)
+#define B_TX_CARRIER (0x1<<1)
+#define B_RX_CARRIER (0x1<<0)
+
+struct hso_serial_state_notification {
+ u8 bmRequestType;
+ u8 bNotification;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+ u16 UART_state_bitmap;
+} __attribute__((packed));
+
+struct hso_tiocmget {
+ struct mutex mutex;
+ wait_queue_head_t waitq;
+ int intr_completed;
+ struct usb_endpoint_descriptor *endp;
+ struct urb *urb;
+ struct hso_serial_state_notification serial_state_notification;
+ u16 prev_UART_state_bitmap;
+ struct uart_icount icount;
+};
+
+
struct hso_serial {
struct hso_device *parent;
int magic;
@@ -219,6 +259,7 @@
spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial);
+ struct hso_tiocmget *tiocmget;
/* Hacks required to get flow control
* working on the serial receive buffers
* so as not to drop characters on the floor.
@@ -310,7 +351,7 @@
static void async_put_intf(struct work_struct *data);
static int hso_put_activity(struct hso_device *hso_dev);
static int hso_get_activity(struct hso_device *hso_dev);
-
+static void tiocmget_intr_callback(struct urb *urb);
/*****************************************************************************/
/* Helping functions */
/*****************************************************************************/
@@ -1460,25 +1501,217 @@
return chars;
}
+int tiocmget_submit_urb(struct hso_serial *serial,
+ struct hso_tiocmget *tiocmget,
+ struct usb_device *usb)
+{
+ int result;
+
+ if (serial->parent->usb_gone)
+ return -ENODEV;
+ usb_fill_int_urb(tiocmget->urb, usb,
+ usb_rcvintpipe(usb,
+ tiocmget->endp->
+ bEndpointAddress & 0x7F),
+ &tiocmget->serial_state_notification,
+ sizeof(struct hso_serial_state_notification),
+ tiocmget_intr_callback, serial,
+ tiocmget->endp->bInterval);
+ result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
+ if (result) {
+ dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
+ result);
+ }
+ return result;
+
+}
+
+static void tiocmget_intr_callback(struct urb *urb)
+{
+ struct hso_serial *serial = urb->context;
+ struct hso_tiocmget *tiocmget;
+ int status = urb->status;
+ u16 UART_state_bitmap, prev_UART_state_bitmap;
+ struct uart_icount *icount;
+ struct hso_serial_state_notification *serial_state_notification;
+ struct usb_device *usb;
+
+ /* Sanity checks */
+ if (!serial)
+ return;
+ if (status) {
+ log_usb_status(status, __func__);
+ return;
+ }
+ tiocmget = serial->tiocmget;
+ if (!tiocmget)
+ return;
+ usb = serial->parent->usb;
+ serial_state_notification = &tiocmget->serial_state_notification;
+ if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
+ serial_state_notification->bNotification != B_NOTIFICATION ||
+ le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
+ le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
+ le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
+ dev_warn(&usb->dev,
+ "hso received invalid serial state notification\n");
+ DUMP(serial_state_notification,
+ sizeof(hso_serial_state_notifation))
+ } else {
+
+ UART_state_bitmap = le16_to_cpu(serial_state_notification->
+ UART_state_bitmap);
+ prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
+ icount = &tiocmget->icount;
+ spin_lock(&serial->serial_lock);
+ if ((UART_state_bitmap & B_OVERRUN) !=
+ (prev_UART_state_bitmap & B_OVERRUN))
+ icount->parity++;
+ if ((UART_state_bitmap & B_PARITY) !=
+ (prev_UART_state_bitmap & B_PARITY))
+ icount->parity++;
+ if ((UART_state_bitmap & B_FRAMING) !=
+ (prev_UART_state_bitmap & B_FRAMING))
+ icount->frame++;
+ if ((UART_state_bitmap & B_RING_SIGNAL) &&
+ !(prev_UART_state_bitmap & B_RING_SIGNAL))
+ icount->rng++;
+ if ((UART_state_bitmap & B_BREAK) !=
+ (prev_UART_state_bitmap & B_BREAK))
+ icount->brk++;
+ if ((UART_state_bitmap & B_TX_CARRIER) !=
+ (prev_UART_state_bitmap & B_TX_CARRIER))
+ icount->dsr++;
+ if ((UART_state_bitmap & B_RX_CARRIER) !=
+ (prev_UART_state_bitmap & B_RX_CARRIER))
+ icount->dcd++;
+ tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
+ spin_unlock(&serial->serial_lock);
+ tiocmget->intr_completed = 1;
+ wake_up_interruptible(&tiocmget->waitq);
+ }
+ memset(serial_state_notification, 0,
+ sizeof(struct hso_serial_state_notification));
+ tiocmget_submit_urb(serial,
+ tiocmget,
+ serial->parent->usb);
+}
+
+/*
+ * next few functions largely stolen from drivers/serial/serial_core.c
+ */
+/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+static int
+hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct uart_icount cprev, cnow;
+ struct hso_tiocmget *tiocmget;
+ int ret;
+
+ tiocmget = serial->tiocmget;
+ if (!tiocmget)
+ return -ENOENT;
+ /*
+ * note the counters on entry
+ */
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+ add_wait_queue(&tiocmget->waitq, &wait);
+ for (;;) {
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
+ ret = 0;
+ break;
+ }
+ schedule();
+ /* see if a signal did it */
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ cprev = cnow;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&tiocmget->waitq, &wait);
+
+ return ret;
+}
+
+/*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+static int hso_get_count(struct hso_serial *serial,
+ struct serial_icounter_struct __user *icnt)
+{
+ struct serial_icounter_struct icount;
+ struct uart_icount cnow;
+ struct hso_tiocmget *tiocmget = serial->tiocmget;
+
+ if (!tiocmget)
+ return -ENOENT;
+ spin_lock_irq(&serial->serial_lock);
+ memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
+ spin_unlock_irq(&serial->serial_lock);
+
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
+}
+
static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
{
- unsigned int value;
+ int retval;
struct hso_serial *serial = get_serial_by_tty(tty);
- unsigned long flags;
+ struct hso_tiocmget *tiocmget;
+ u16 UART_state_bitmap;
/* sanity check */
if (!serial) {
D1("no tty structures");
return -EINVAL;
}
-
- spin_lock_irqsave(&serial->serial_lock, flags);
- value = ((serial->rts_state) ? TIOCM_RTS : 0) |
+ spin_lock_irq(&serial->serial_lock);
+ retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
((serial->dtr_state) ? TIOCM_DTR : 0);
- spin_unlock_irqrestore(&serial->serial_lock, flags);
+ tiocmget = serial->tiocmget;
+ if (tiocmget) {
- return value;
+ UART_state_bitmap = le16_to_cpu(
+ tiocmget->prev_UART_state_bitmap);
+ if (UART_state_bitmap & B_RING_SIGNAL)
+ retval |= TIOCM_RNG;
+ if (UART_state_bitmap & B_RX_CARRIER)
+ retval |= TIOCM_CD;
+ if (UART_state_bitmap & B_TX_CARRIER)
+ retval |= TIOCM_DSR;
+ }
+ spin_unlock_irq(&serial->serial_lock);
+ return retval;
}
static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
@@ -1520,6 +1753,32 @@
USB_CTRL_SET_TIMEOUT);
}
+static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct hso_serial *serial = get_serial_by_tty(tty);
+ void __user *uarg = (void __user *)arg;
+ int ret = 0;
+ D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
+
+ if (!serial)
+ return -ENODEV;
+ switch (cmd) {
+ case TIOCMIWAIT:
+ ret = hso_wait_modem_status(serial, arg);
+ break;
+
+ case TIOCGICOUNT:
+ ret = hso_get_count(serial, uarg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ return ret;
+}
+
+
/* starts a transmit */
static void hso_kick_transmit(struct hso_serial *serial)
{
@@ -1982,7 +2241,10 @@
serial->shared_int->use_count++;
mutex_unlock(&serial->shared_int->shared_int_lock);
}
-
+ if (serial->tiocmget)
+ tiocmget_submit_urb(serial,
+ serial->tiocmget,
+ serial->parent->usb);
return result;
}
@@ -1990,6 +2252,7 @@
{
int i;
struct hso_serial *serial = dev2ser(hso_dev);
+ struct hso_tiocmget *tiocmget;
if (!serial)
return -ENODEV;
@@ -2018,6 +2281,11 @@
}
mutex_unlock(&serial->shared_int->shared_int_lock);
}
+ tiocmget = serial->tiocmget;
+ if (tiocmget) {
+ wake_up_interruptible(&tiocmget->waitq);
+ usb_kill_urb(tiocmget->urb);
+ }
return 0;
}
@@ -2368,6 +2636,20 @@
return NULL;
}
+static void hso_free_tiomget(struct hso_serial *serial)
+{
+ struct hso_tiocmget *tiocmget = serial->tiocmget;
+ if (tiocmget) {
+ kfree(tiocmget);
+ if (tiocmget->urb) {
+ usb_free_urb(tiocmget->urb);
+ tiocmget->urb = NULL;
+ }
+ serial->tiocmget = NULL;
+
+ }
+}
+
/* Frees an AT channel ( goes for both mux and non-mux ) */
static void hso_free_serial_device(struct hso_device *hso_dev)
{
@@ -2386,6 +2668,7 @@
else
mutex_unlock(&serial->shared_int->shared_int_lock);
}
+ hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
}
@@ -2397,6 +2680,7 @@
struct hso_device *hso_dev;
struct hso_serial *serial;
int num_urbs;
+ struct hso_tiocmget *tiocmget;
hso_dev = hso_create_device(interface, port);
if (!hso_dev)
@@ -2408,9 +2692,27 @@
serial->parent = hso_dev;
hso_dev->port_data.dev_serial = serial;
-
- if (port & HSO_PORT_MODEM)
+ if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
num_urbs = 2;
+ serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
+ GFP_KERNEL);
+ /* it isn't going to break our heart if serial->tiocmget
+ * allocation fails don't bother checking this.
+ */
+ if (serial->tiocmget) {
+ tiocmget = serial->tiocmget;
+ tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (tiocmget->urb) {
+ mutex_init(&tiocmget->mutex);
+ init_waitqueue_head(&tiocmget->waitq);
+ tiocmget->endp = hso_get_ep(
+ interface,
+ USB_ENDPOINT_XFER_INT,
+ USB_DIR_IN);
+ } else
+ hso_free_tiomget(serial);
+ }
+ }
else
num_urbs = 1;
@@ -2446,6 +2748,7 @@
exit2:
hso_serial_common_free(serial);
exit:
+ hso_free_tiomget(serial);
kfree(serial);
hso_free_device(hso_dev);
return NULL;
@@ -2958,6 +3261,7 @@
.close = hso_serial_close,
.write = hso_serial_write,
.write_room = hso_serial_write_room,
+ .ioctl = hso_serial_ioctl,
.set_termios = hso_serial_set_termios,
.chars_in_buffer = hso_serial_chars_in_buffer,
.tiocmget = hso_serial_tiocmget,
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 1/3] hso modem signals patch fix
[not found] ` <493CF8F5.30007-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
@ 2008-12-08 10:53 ` David Miller
0 siblings, 0 replies; 3+ messages in thread
From: David Miller @ 2008-12-08 10:53 UTC (permalink / raw)
To: D.Barow-x9gZzRpC1QbQT0dZR+AlfA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
alan-qBU/x9rampVanCEyBjwyrvXRex20P6io
From: Denis Joseph Barrow <D.Barow-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
Date: Mon, 08 Dec 2008 11:37:41 +0100
You probably want to CC: Alan Cox on patches of this nature,
which I've done here.
> This patch is a respin of a previously sent patch,
> I inherited a bug from previous code on detecting the modem
> port which causes a crash on opening control ports doing
> because the check
> if (port & HSO_PORT_MODEM)
> should be
> if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
> & a urb gets submitted to a non existent endpoint.
>
> Makes TIOCM ioctls for Data Carrier Detect & related functions
> work like /drivers/serial/serial-core.c potentially needed
> for pppd & similar user programs.
> Signed-off-by: Denis Joseph Barrow <D.Barow-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
> ---
> Index: linux-2.6.28-rc6.patches/drivers/net/usb/hso.c
> ===================================================================
> --- linux-2.6.28-rc6.patches.orig/drivers/net/usb/hso.c 2008-11-24 17:07:07.000000000 +0100
> +++ linux-2.6.28-rc6.patches/drivers/net/usb/hso.c 2008-12-08 11:18:55.000000000 +0100
> @@ -39,8 +39,11 @@
> * port is opened, as this have a huge impact on the network port
> * throughput.
> *
> - * Interface 2: Standard modem interface - circuit switched interface, should
> - * not be used.
> + * Interface 2: Standard modem interface - circuit switched interface, this
> + * can be used to make a standard ppp connection however it
> + * should not be used in conjunction with the IP network interface
> + * enabled for USB performance reasons i.e. if using this set
> + * ideally disable_net=1.
> *
> *****************************************************************************/
>
> @@ -63,6 +66,8 @@
> #include <linux/usb/cdc.h>
> #include <net/arp.h>
> #include <asm/byteorder.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial.h>
>
>
> #define DRIVER_VERSION "1.2"
> @@ -182,6 +187,41 @@
> RX_PENDING
> };
>
> +#define BM_REQUEST_TYPE (0xa1)
> +#define B_NOTIFICATION (0x20)
> +#define W_VALUE (0x0)
> +#define W_INDEX (0x2)
> +#define W_LENGTH (0x2)
> +
> +#define B_OVERRUN (0x1<<6)
> +#define B_PARITY (0x1<<5)
> +#define B_FRAMING (0x1<<4)
> +#define B_RING_SIGNAL (0x1<<3)
> +#define B_BREAK (0x1<<2)
> +#define B_TX_CARRIER (0x1<<1)
> +#define B_RX_CARRIER (0x1<<0)
> +
> +struct hso_serial_state_notification {
> + u8 bmRequestType;
> + u8 bNotification;
> + u16 wValue;
> + u16 wIndex;
> + u16 wLength;
> + u16 UART_state_bitmap;
> +} __attribute__((packed));
> +
> +struct hso_tiocmget {
> + struct mutex mutex;
> + wait_queue_head_t waitq;
> + int intr_completed;
> + struct usb_endpoint_descriptor *endp;
> + struct urb *urb;
> + struct hso_serial_state_notification serial_state_notification;
> + u16 prev_UART_state_bitmap;
> + struct uart_icount icount;
> +};
> +
> +
> struct hso_serial {
> struct hso_device *parent;
> int magic;
> @@ -219,6 +259,7 @@
> spinlock_t serial_lock;
>
> int (*write_data) (struct hso_serial *serial);
> + struct hso_tiocmget *tiocmget;
> /* Hacks required to get flow control
> * working on the serial receive buffers
> * so as not to drop characters on the floor.
> @@ -310,7 +351,7 @@
> static void async_put_intf(struct work_struct *data);
> static int hso_put_activity(struct hso_device *hso_dev);
> static int hso_get_activity(struct hso_device *hso_dev);
> -
> +static void tiocmget_intr_callback(struct urb *urb);
> /*****************************************************************************/
> /* Helping functions */
> /*****************************************************************************/
> @@ -1460,25 +1501,217 @@
>
> return chars;
> }
> +int tiocmget_submit_urb(struct hso_serial *serial,
> + struct hso_tiocmget *tiocmget,
> + struct usb_device *usb)
> +{
> + int result;
> +
> + if (serial->parent->usb_gone)
> + return -ENODEV;
> + usb_fill_int_urb(tiocmget->urb, usb,
> + usb_rcvintpipe(usb,
> + tiocmget->endp->
> + bEndpointAddress & 0x7F),
> + &tiocmget->serial_state_notification,
> + sizeof(struct hso_serial_state_notification),
> + tiocmget_intr_callback, serial,
> + tiocmget->endp->bInterval);
> + result = usb_submit_urb(tiocmget->urb, GFP_ATOMIC);
> + if (result) {
> + dev_warn(&usb->dev, "%s usb_submit_urb failed %d\n", __func__,
> + result);
> + }
> + return result;
> +
> +}
> +
> +static void tiocmget_intr_callback(struct urb *urb)
> +{
> + struct hso_serial *serial = urb->context;
> + struct hso_tiocmget *tiocmget;
> + int status = urb->status;
> + u16 UART_state_bitmap, prev_UART_state_bitmap;
> + struct uart_icount *icount;
> + struct hso_serial_state_notification *serial_state_notification;
> + struct usb_device *usb;
> +
> + /* Sanity checks */
> + if (!serial)
> + return;
> + if (status) {
> + log_usb_status(status, __func__);
> + return;
> + }
> + tiocmget = serial->tiocmget;
> + if (!tiocmget)
> + return;
> + usb = serial->parent->usb;
> + serial_state_notification = &tiocmget->serial_state_notification;
> + if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE ||
> + serial_state_notification->bNotification != B_NOTIFICATION ||
> + le16_to_cpu(serial_state_notification->wValue) != W_VALUE ||
> + le16_to_cpu(serial_state_notification->wIndex) != W_INDEX ||
> + le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) {
> + dev_warn(&usb->dev,
> + "hso received invalid serial state notification\n");
> + DUMP(serial_state_notification,
> + sizeof(hso_serial_state_notifation))
> + } else {
> +
> + UART_state_bitmap = le16_to_cpu(serial_state_notification->
> + UART_state_bitmap);
> + prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
> + icount = &tiocmget->icount;
> + spin_lock(&serial->serial_lock);
> + if ((UART_state_bitmap & B_OVERRUN) !=
> + (prev_UART_state_bitmap & B_OVERRUN))
> + icount->parity++;
> + if ((UART_state_bitmap & B_PARITY) !=
> + (prev_UART_state_bitmap & B_PARITY))
> + icount->parity++;
> + if ((UART_state_bitmap & B_FRAMING) !=
> + (prev_UART_state_bitmap & B_FRAMING))
> + icount->frame++;
> + if ((UART_state_bitmap & B_RING_SIGNAL) &&
> + !(prev_UART_state_bitmap & B_RING_SIGNAL))
> + icount->rng++;
> + if ((UART_state_bitmap & B_BREAK) !=
> + (prev_UART_state_bitmap & B_BREAK))
> + icount->brk++;
> + if ((UART_state_bitmap & B_TX_CARRIER) !=
> + (prev_UART_state_bitmap & B_TX_CARRIER))
> + icount->dsr++;
> + if ((UART_state_bitmap & B_RX_CARRIER) !=
> + (prev_UART_state_bitmap & B_RX_CARRIER))
> + icount->dcd++;
> + tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
> + spin_unlock(&serial->serial_lock);
> + tiocmget->intr_completed = 1;
> + wake_up_interruptible(&tiocmget->waitq);
> + }
> + memset(serial_state_notification, 0,
> + sizeof(struct hso_serial_state_notification));
> + tiocmget_submit_urb(serial,
> + tiocmget,
> + serial->parent->usb);
> +}
> +
> +/*
> + * next few functions largely stolen from drivers/serial/serial_core.c
> + */
> +/* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
> + * - mask passed in arg for lines of interest
> + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
> + * Caller should use TIOCGICOUNT to see which one it was
> + */
> +static int
> +hso_wait_modem_status(struct hso_serial *serial, unsigned long arg)
> +{
> + DECLARE_WAITQUEUE(wait, current);
> + struct uart_icount cprev, cnow;
> + struct hso_tiocmget *tiocmget;
> + int ret;
> +
> + tiocmget = serial->tiocmget;
> + if (!tiocmget)
> + return -ENOENT;
> + /*
> + * note the counters on entry
> + */
> + spin_lock_irq(&serial->serial_lock);
> + memcpy(&cprev, &tiocmget->icount, sizeof(struct uart_icount));
> + spin_unlock_irq(&serial->serial_lock);
> + add_wait_queue(&tiocmget->waitq, &wait);
> + for (;;) {
> + spin_lock_irq(&serial->serial_lock);
> + memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
> + spin_unlock_irq(&serial->serial_lock);
> + set_current_state(TASK_INTERRUPTIBLE);
> + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
> + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
> + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd))) {
> + ret = 0;
> + break;
> + }
> + schedule();
> + /* see if a signal did it */
> + if (signal_pending(current)) {
> + ret = -ERESTARTSYS;
> + break;
> + }
> + cprev = cnow;
> + }
> + current->state = TASK_RUNNING;
> + remove_wait_queue(&tiocmget->waitq, &wait);
> +
> + return ret;
> +}
> +
> +/*
> + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
> + * Return: write counters to the user passed counter struct
> + * NB: both 1->0 and 0->1 transitions are counted except for
> + * RI where only 0->1 is counted.
> + */
> +static int hso_get_count(struct hso_serial *serial,
> + struct serial_icounter_struct __user *icnt)
> +{
> + struct serial_icounter_struct icount;
> + struct uart_icount cnow;
> + struct hso_tiocmget *tiocmget = serial->tiocmget;
> +
> + if (!tiocmget)
> + return -ENOENT;
> + spin_lock_irq(&serial->serial_lock);
> + memcpy(&cnow, &tiocmget->icount, sizeof(struct uart_icount));
> + spin_unlock_irq(&serial->serial_lock);
> +
> + icount.cts = cnow.cts;
> + icount.dsr = cnow.dsr;
> + icount.rng = cnow.rng;
> + icount.dcd = cnow.dcd;
> + icount.rx = cnow.rx;
> + icount.tx = cnow.tx;
> + icount.frame = cnow.frame;
> + icount.overrun = cnow.overrun;
> + icount.parity = cnow.parity;
> + icount.brk = cnow.brk;
> + icount.buf_overrun = cnow.buf_overrun;
> +
> + return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
> +}
> +
>
> static int hso_serial_tiocmget(struct tty_struct *tty, struct file *file)
> {
> - unsigned int value;
> + int retval;
> struct hso_serial *serial = get_serial_by_tty(tty);
> - unsigned long flags;
> + struct hso_tiocmget *tiocmget;
> + u16 UART_state_bitmap;
>
> /* sanity check */
> if (!serial) {
> D1("no tty structures");
> return -EINVAL;
> }
> -
> - spin_lock_irqsave(&serial->serial_lock, flags);
> - value = ((serial->rts_state) ? TIOCM_RTS : 0) |
> + spin_lock_irq(&serial->serial_lock);
> + retval = ((serial->rts_state) ? TIOCM_RTS : 0) |
> ((serial->dtr_state) ? TIOCM_DTR : 0);
> - spin_unlock_irqrestore(&serial->serial_lock, flags);
> + tiocmget = serial->tiocmget;
> + if (tiocmget) {
>
> - return value;
> + UART_state_bitmap = le16_to_cpu(
> + tiocmget->prev_UART_state_bitmap);
> + if (UART_state_bitmap & B_RING_SIGNAL)
> + retval |= TIOCM_RNG;
> + if (UART_state_bitmap & B_RX_CARRIER)
> + retval |= TIOCM_CD;
> + if (UART_state_bitmap & B_TX_CARRIER)
> + retval |= TIOCM_DSR;
> + }
> + spin_unlock_irq(&serial->serial_lock);
> + return retval;
> }
>
> static int hso_serial_tiocmset(struct tty_struct *tty, struct file *file,
> @@ -1520,6 +1753,32 @@
> USB_CTRL_SET_TIMEOUT);
> }
>
> +static int hso_serial_ioctl(struct tty_struct *tty, struct file *file,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct hso_serial *serial = get_serial_by_tty(tty);
> + void __user *uarg = (void __user *)arg;
> + int ret = 0;
> + D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
> +
> + if (!serial)
> + return -ENODEV;
> + switch (cmd) {
> + case TIOCMIWAIT:
> + ret = hso_wait_modem_status(serial, arg);
> + break;
> +
> + case TIOCGICOUNT:
> + ret = hso_get_count(serial, uarg);
> + break;
> + default:
> + ret = -ENOIOCTLCMD;
> + break;
> + }
> + return ret;
> +}
> +
> +
> /* starts a transmit */
> static void hso_kick_transmit(struct hso_serial *serial)
> {
> @@ -1982,7 +2241,10 @@
> serial->shared_int->use_count++;
> mutex_unlock(&serial->shared_int->shared_int_lock);
> }
> -
> + if (serial->tiocmget)
> + tiocmget_submit_urb(serial,
> + serial->tiocmget,
> + serial->parent->usb);
> return result;
> }
>
> @@ -1990,6 +2252,7 @@
> {
> int i;
> struct hso_serial *serial = dev2ser(hso_dev);
> + struct hso_tiocmget *tiocmget;
>
> if (!serial)
> return -ENODEV;
> @@ -2018,6 +2281,11 @@
> }
> mutex_unlock(&serial->shared_int->shared_int_lock);
> }
> + tiocmget = serial->tiocmget;
> + if (tiocmget) {
> + wake_up_interruptible(&tiocmget->waitq);
> + usb_kill_urb(tiocmget->urb);
> + }
>
> return 0;
> }
> @@ -2368,6 +2636,20 @@
> return NULL;
> }
>
> +static void hso_free_tiomget(struct hso_serial *serial)
> +{
> + struct hso_tiocmget *tiocmget = serial->tiocmget;
> + if (tiocmget) {
> + kfree(tiocmget);
> + if (tiocmget->urb) {
> + usb_free_urb(tiocmget->urb);
> + tiocmget->urb = NULL;
> + }
> + serial->tiocmget = NULL;
> +
> + }
> +}
> +
> /* Frees an AT channel ( goes for both mux and non-mux ) */
> static void hso_free_serial_device(struct hso_device *hso_dev)
> {
> @@ -2386,6 +2668,7 @@
> else
> mutex_unlock(&serial->shared_int->shared_int_lock);
> }
> + hso_free_tiomget(serial);
> kfree(serial);
> hso_free_device(hso_dev);
> }
> @@ -2397,6 +2680,7 @@
> struct hso_device *hso_dev;
> struct hso_serial *serial;
> int num_urbs;
> + struct hso_tiocmget *tiocmget;
>
> hso_dev = hso_create_device(interface, port);
> if (!hso_dev)
> @@ -2408,9 +2692,27 @@
>
> serial->parent = hso_dev;
> hso_dev->port_data.dev_serial = serial;
> -
> - if (port & HSO_PORT_MODEM)
> + if ((port & HSO_PORT_MASK) == HSO_PORT_MODEM) {
> num_urbs = 2;
> + serial->tiocmget = kzalloc(sizeof(struct hso_tiocmget),
> + GFP_KERNEL);
> + /* it isn't going to break our heart if serial->tiocmget
> + * allocation fails don't bother checking this.
> + */
> + if (serial->tiocmget) {
> + tiocmget = serial->tiocmget;
> + tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL);
> + if (tiocmget->urb) {
> + mutex_init(&tiocmget->mutex);
> + init_waitqueue_head(&tiocmget->waitq);
> + tiocmget->endp = hso_get_ep(
> + interface,
> + USB_ENDPOINT_XFER_INT,
> + USB_DIR_IN);
> + } else
> + hso_free_tiomget(serial);
> + }
> + }
> else
> num_urbs = 1;
>
> @@ -2446,6 +2748,7 @@
> exit2:
> hso_serial_common_free(serial);
> exit:
> + hso_free_tiomget(serial);
> kfree(serial);
> hso_free_device(hso_dev);
> return NULL;
> @@ -2958,6 +3261,7 @@
> .close = hso_serial_close,
> .write = hso_serial_write,
> .write_room = hso_serial_write_room,
> + .ioctl = hso_serial_ioctl,
> .set_termios = hso_serial_set_termios,
> .chars_in_buffer = hso_serial_chars_in_buffer,
> .tiocmget = hso_serial_tiocmget,
>
> --
> best regards,
> D.J. Barrow
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 1/3] hso modem signals patch fix
2008-12-08 10:37 [PATCH 1/3] hso modem signals patch fix Denis Joseph Barrow
[not found] ` <493CF8F5.30007-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
@ 2008-12-08 11:34 ` Alan Cox
1 sibling, 0 replies; 3+ messages in thread
From: Alan Cox @ 2008-12-08 11:34 UTC (permalink / raw)
To: Denis Joseph Barrow
Cc: Linux netdev Mailing list, Linux USB kernel mailing list
> Makes TIOCM ioctls for Data Carrier Detect & related functions
> work like /drivers/serial/serial-core.c potentially needed
> for pppd & similar user programs.
> Signed-off-by: Denis Joseph Barrow <D.Barow@option.com>
Doesn't apply versus the current ttydev tree stack which has other hso
related patches in it including a previous modem patch you sent. Please
send updates versus the current ttydev tree and your previous patch.
http://zeniv.linux.org.uk/~alan has the ttydev patch stack. If the most
sensible thing to do is to drop your old patch and swap in a version of
this one then that is fine but let me know what should happen to it.
Also please send/cc tty related patches to me. I appreciate this is also
a network driver but the tty side stuff really does need to go via ttydev
as there are a lot of tty changes currently going on.
NAK this therefore
Alan
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-12-08 11:34 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-08 10:37 [PATCH 1/3] hso modem signals patch fix Denis Joseph Barrow
[not found] ` <493CF8F5.30007-x9gZzRpC1QbQT0dZR+AlfA@public.gmane.org>
2008-12-08 10:53 ` David Miller
2008-12-08 11:34 ` Alan Cox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).