|
@@ -183,7 +183,10 @@
|
|
|
#define LED_ON_MS 500
|
|
|
#define LED_OFF_MS 500
|
|
|
|
|
|
-static int device_type;
|
|
|
+enum mos7840_flag {
|
|
|
+ MOS7840_FLAG_CTRL_BUSY,
|
|
|
+ MOS7840_FLAG_LED_BUSY,
|
|
|
+};
|
|
|
|
|
|
static const struct usb_device_id id_table[] = {
|
|
|
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
|
|
@@ -238,9 +241,12 @@ struct moschip_port {
|
|
|
|
|
|
/* For device(s) with LED indicator */
|
|
|
bool has_led;
|
|
|
- bool led_flag;
|
|
|
struct timer_list led_timer1; /* Timer for LED on */
|
|
|
struct timer_list led_timer2; /* Timer for LED off */
|
|
|
+ struct urb *led_urb;
|
|
|
+ struct usb_ctrlrequest *led_dr;
|
|
|
+
|
|
|
+ unsigned long flags;
|
|
|
};
|
|
|
|
|
|
/*
|
|
@@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb)
|
|
|
case -ESHUTDOWN:
|
|
|
/* this urb is terminated, clean up */
|
|
|
dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
|
|
|
- return;
|
|
|
+ goto out;
|
|
|
default:
|
|
|
dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
|
|
|
- return;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
|
|
@@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb)
|
|
|
mos7840_handle_new_msr(mos7840_port, regval);
|
|
|
else if (mos7840_port->MsrLsr == 1)
|
|
|
mos7840_handle_new_lsr(mos7840_port, regval);
|
|
|
+out:
|
|
|
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
|
|
|
}
|
|
|
|
|
|
static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
|
@@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
|
|
unsigned char *buffer = mcs->ctrl_buf;
|
|
|
int ret;
|
|
|
|
|
|
+ if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
dr->bRequestType = MCS_RD_RTYPE;
|
|
|
dr->bRequest = MCS_RDREQ;
|
|
|
dr->wValue = cpu_to_le16(Wval); /* 0 */
|
|
@@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
|
|
|
mos7840_control_callback, mcs);
|
|
|
mcs->control_urb->transfer_buffer_length = 2;
|
|
|
ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
|
|
|
+ if (ret)
|
|
|
+ clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -523,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
|
|
|
__u16 reg)
|
|
|
{
|
|
|
struct usb_device *dev = mcs->port->serial->dev;
|
|
|
- struct usb_ctrlrequest *dr = mcs->dr;
|
|
|
+ struct usb_ctrlrequest *dr = mcs->led_dr;
|
|
|
|
|
|
dr->bRequestType = MCS_WR_RTYPE;
|
|
|
dr->bRequest = MCS_WRREQ;
|
|
@@ -531,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
|
|
|
dr->wIndex = cpu_to_le16(reg);
|
|
|
dr->wLength = cpu_to_le16(0);
|
|
|
|
|
|
- usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
|
|
|
+ usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
|
|
|
(unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
|
|
|
|
|
|
- usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
|
|
|
+ usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
|
|
|
}
|
|
|
|
|
|
static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
|
|
@@ -560,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg)
|
|
|
{
|
|
|
struct moschip_port *mcs = (struct moschip_port *) arg;
|
|
|
|
|
|
- mcs->led_flag = false;
|
|
|
+ clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void mos7840_led_activity(struct usb_serial_port *port)
|
|
|
+{
|
|
|
+ struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
|
|
|
+
|
|
|
+ if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
|
|
|
+ return;
|
|
|
+
|
|
|
+ mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
|
|
|
+ mod_timer(&mos7840_port->led_timer1,
|
|
|
+ jiffies + msecs_to_jiffies(LED_ON_MS));
|
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
@@ -758,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- /* Turn on LED */
|
|
|
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
|
|
|
- mos7840_port->led_flag = true;
|
|
|
- mos7840_set_led_async(mos7840_port, 0x0301,
|
|
|
- MODEM_CONTROL_REGISTER);
|
|
|
- mod_timer(&mos7840_port->led_timer1,
|
|
|
- jiffies + msecs_to_jiffies(LED_ON_MS));
|
|
|
- }
|
|
|
+ if (mos7840_port->has_led)
|
|
|
+ mos7840_led_activity(port);
|
|
|
|
|
|
mos7840_port->read_urb_busy = true;
|
|
|
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
|
|
@@ -816,18 +836,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
|
|
|
/************************************************************************/
|
|
|
/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
|
|
|
/************************************************************************/
|
|
|
-#ifdef MCSSerialProbe
|
|
|
-static int mos7840_serial_probe(struct usb_serial *serial,
|
|
|
- const struct usb_device_id *id)
|
|
|
-{
|
|
|
-
|
|
|
- /*need to implement the mode_reg reading and updating\
|
|
|
- structures usb_serial_ device_type\
|
|
|
- (i.e num_ports, num_bulkin,bulkout etc) */
|
|
|
- /* Also we can update the changes attach */
|
|
|
- return 1;
|
|
|
-}
|
|
|
-#endif
|
|
|
|
|
|
/*****************************************************************************
|
|
|
* mos7840_open
|
|
@@ -1454,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
data1 = urb->transfer_buffer;
|
|
|
dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
|
|
|
|
|
|
- /* Turn on LED */
|
|
|
- if (mos7840_port->has_led && !mos7840_port->led_flag) {
|
|
|
- mos7840_port->led_flag = true;
|
|
|
- mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
|
|
|
- mod_timer(&mos7840_port->led_timer1,
|
|
|
- jiffies + msecs_to_jiffies(LED_ON_MS));
|
|
|
- }
|
|
|
+ if (mos7840_port->has_led)
|
|
|
+ mos7840_led_activity(port);
|
|
|
|
|
|
/* send it down the pipe */
|
|
|
status = usb_submit_urb(urb, GFP_ATOMIC);
|
|
@@ -2187,38 +2190,48 @@ static int mos7810_check(struct usb_serial *serial)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int mos7840_calc_num_ports(struct usb_serial *serial)
|
|
|
+static int mos7840_probe(struct usb_serial *serial,
|
|
|
+ const struct usb_device_id *id)
|
|
|
{
|
|
|
- __u16 data = 0x00;
|
|
|
+ u16 product = serial->dev->descriptor.idProduct;
|
|
|
u8 *buf;
|
|
|
- int mos7840_num_ports;
|
|
|
+ int device_type;
|
|
|
+
|
|
|
+ if (product == MOSCHIP_DEVICE_ID_7810 ||
|
|
|
+ product == MOSCHIP_DEVICE_ID_7820) {
|
|
|
+ device_type = product;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
|
|
|
- if (buf) {
|
|
|
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
|
|
|
+ if (!buf)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
|
|
|
MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
|
|
|
VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
|
|
|
- data = *buf;
|
|
|
- kfree(buf);
|
|
|
- }
|
|
|
|
|
|
- if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
|
|
|
- serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
|
|
|
- device_type = serial->dev->descriptor.idProduct;
|
|
|
- } else {
|
|
|
- /* For a MCS7840 device GPIO0 must be set to 1 */
|
|
|
- if ((data & 0x01) == 1)
|
|
|
- device_type = MOSCHIP_DEVICE_ID_7840;
|
|
|
- else if (mos7810_check(serial))
|
|
|
- device_type = MOSCHIP_DEVICE_ID_7810;
|
|
|
- else
|
|
|
- device_type = MOSCHIP_DEVICE_ID_7820;
|
|
|
- }
|
|
|
+ /* For a MCS7840 device GPIO0 must be set to 1 */
|
|
|
+ if (buf[0] & 0x01)
|
|
|
+ device_type = MOSCHIP_DEVICE_ID_7840;
|
|
|
+ else if (mos7810_check(serial))
|
|
|
+ device_type = MOSCHIP_DEVICE_ID_7810;
|
|
|
+ else
|
|
|
+ device_type = MOSCHIP_DEVICE_ID_7820;
|
|
|
+
|
|
|
+ kfree(buf);
|
|
|
+out:
|
|
|
+ usb_set_serial_data(serial, (void *)(unsigned long)device_type);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mos7840_calc_num_ports(struct usb_serial *serial)
|
|
|
+{
|
|
|
+ int device_type = (unsigned long)usb_get_serial_data(serial);
|
|
|
+ int mos7840_num_ports;
|
|
|
|
|
|
mos7840_num_ports = (device_type >> 4) & 0x000F;
|
|
|
- serial->num_bulk_in = mos7840_num_ports;
|
|
|
- serial->num_bulk_out = mos7840_num_ports;
|
|
|
- serial->num_ports = mos7840_num_ports;
|
|
|
|
|
|
return mos7840_num_ports;
|
|
|
}
|
|
@@ -2226,6 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
|
|
|
static int mos7840_port_probe(struct usb_serial_port *port)
|
|
|
{
|
|
|
struct usb_serial *serial = port->serial;
|
|
|
+ int device_type = (unsigned long)usb_get_serial_data(serial);
|
|
|
struct moschip_port *mos7840_port;
|
|
|
int status;
|
|
|
int pnum;
|
|
@@ -2401,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
|
|
|
if (device_type == MOSCHIP_DEVICE_ID_7810) {
|
|
|
mos7840_port->has_led = true;
|
|
|
|
|
|
+ mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
|
|
|
+ mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
|
|
|
+ status = -ENOMEM;
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+
|
|
|
init_timer(&mos7840_port->led_timer1);
|
|
|
mos7840_port->led_timer1.function = mos7840_led_off;
|
|
|
mos7840_port->led_timer1.expires =
|
|
@@ -2413,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
|
|
|
jiffies + msecs_to_jiffies(LED_OFF_MS);
|
|
|
mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
|
|
|
|
|
|
- mos7840_port->led_flag = false;
|
|
|
-
|
|
|
/* Turn off LED */
|
|
|
mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
|
|
|
}
|
|
@@ -2436,6 +2456,8 @@ out:
|
|
|
}
|
|
|
return 0;
|
|
|
error:
|
|
|
+ kfree(mos7840_port->led_dr);
|
|
|
+ usb_free_urb(mos7840_port->led_urb);
|
|
|
kfree(mos7840_port->dr);
|
|
|
kfree(mos7840_port->ctrl_buf);
|
|
|
usb_free_urb(mos7840_port->control_urb);
|
|
@@ -2456,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
|
|
|
|
|
|
del_timer_sync(&mos7840_port->led_timer1);
|
|
|
del_timer_sync(&mos7840_port->led_timer2);
|
|
|
+
|
|
|
+ usb_kill_urb(mos7840_port->led_urb);
|
|
|
+ usb_free_urb(mos7840_port->led_urb);
|
|
|
+ kfree(mos7840_port->led_dr);
|
|
|
}
|
|
|
usb_kill_urb(mos7840_port->control_urb);
|
|
|
usb_free_urb(mos7840_port->control_urb);
|
|
@@ -2482,9 +2508,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
|
|
|
.throttle = mos7840_throttle,
|
|
|
.unthrottle = mos7840_unthrottle,
|
|
|
.calc_num_ports = mos7840_calc_num_ports,
|
|
|
-#ifdef MCSSerialProbe
|
|
|
- .probe = mos7840_serial_probe,
|
|
|
-#endif
|
|
|
+ .probe = mos7840_probe,
|
|
|
.ioctl = mos7840_ioctl,
|
|
|
.set_termios = mos7840_set_termios,
|
|
|
.break_ctl = mos7840_break,
|