Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (29 commits) ARM: imx: fix build failure concerning otg/ulpi USB: ftdi_sio: add product ID for Lenz LI-USB USB: adutux: fix misuse of return value of copy_to_user() USB: iowarrior: fix misuse of return value of copy_to_user() USB: xHCI: update ring dequeue pointer when process missed tds USB: xhci: Remove buggy assignment in next_trb() USB: ftdi_sio: Add ID for Ionics PlugComputer USB: serial: io_ti.c: don't return 0 if writing the download record failed USB: otg: twl4030: fix wrong assumption of starting state USB: gadget: Return -ENOMEM on memory allocation failure USB: gadget: fix composite kernel-doc warnings USB: ssu100: set tty_flags in ssu100_process_packet USB: ssu100: add disconnect function for ssu100 USB: serial: export symbol usb_serial_generic_disconnect USB: ssu100: rework logic for TIOCMIWAIT USB: ssu100: add register parameter to ssu100_setregister USB: ssu100: remove duplicate #defines in ssu100 USB: ssu100: refine process_packet in ssu100 USB: ssu100: add locking for port private data in ssu100 USB: r8a66597-udc: return -ENOMEM if kzalloc() fails ...
This commit is contained in:
Коммит
d20de76354
|
@ -279,13 +279,13 @@ static void __init eukrea_cpuimx27_init(void)
|
||||||
#if defined(CONFIG_USB_ULPI)
|
#if defined(CONFIG_USB_ULPI)
|
||||||
if (otg_mode_host) {
|
if (otg_mode_host) {
|
||||||
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
|
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -419,13 +419,13 @@ static void __init pca100_init(void)
|
||||||
#if defined(CONFIG_USB_ULPI)
|
#if defined(CONFIG_USB_ULPI)
|
||||||
if (otg_mode_host) {
|
if (otg_mode_host) {
|
||||||
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
|
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -138,7 +138,7 @@ static void __init eukrea_cpuimx25_init(void)
|
||||||
#if defined(CONFIG_USB_ULPI)
|
#if defined(CONFIG_USB_ULPI)
|
||||||
if (otg_mode_host) {
|
if (otg_mode_host) {
|
||||||
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_otg, &otg_pdata);
|
mxc_register_device(&mxc_otg, &otg_pdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ static void __init mxc_board_init(void)
|
||||||
#if defined(CONFIG_USB_ULPI)
|
#if defined(CONFIG_USB_ULPI)
|
||||||
if (otg_mode_host) {
|
if (otg_mode_host) {
|
||||||
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
|
||||||
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
|
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
|
||||||
|
|
||||||
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
mxc_register_device(&mxc_otg_host, &otg_pdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -723,12 +723,12 @@ int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* usb_string_ids_n() - allocate unused string IDs in batch
|
* usb_string_ids_n() - allocate unused string IDs in batch
|
||||||
* @cdev: the device whose string descriptor IDs are being allocated
|
* @c: the device whose string descriptor IDs are being allocated
|
||||||
* @n: number of string IDs to allocate
|
* @n: number of string IDs to allocate
|
||||||
* Context: single threaded during gadget setup
|
* Context: single threaded during gadget setup
|
||||||
*
|
*
|
||||||
* Returns the first requested ID. This ID and next @n-1 IDs are now
|
* Returns the first requested ID. This ID and next @n-1 IDs are now
|
||||||
* valid IDs. At least providind that @n is non zore because if it
|
* valid IDs. At least provided that @n is non-zero because if it
|
||||||
* is, returns last requested ID which is now very useful information.
|
* is, returns last requested ID which is now very useful information.
|
||||||
*
|
*
|
||||||
* @usb_string_ids_n() is called from bind() callbacks to allocate
|
* @usb_string_ids_n() is called from bind() callbacks to allocate
|
||||||
|
|
|
@ -1609,6 +1609,7 @@ static int __init m66592_probe(struct platform_device *pdev)
|
||||||
/* initialize ucd */
|
/* initialize ucd */
|
||||||
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
|
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
|
||||||
if (m66592 == NULL) {
|
if (m66592 == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
pr_err("kzalloc error\n");
|
pr_err("kzalloc error\n");
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1557,6 +1557,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
|
||||||
/* initialize ucd */
|
/* initialize ucd */
|
||||||
r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);
|
r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);
|
||||||
if (r8a66597 == NULL) {
|
if (r8a66597 == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
printk(KERN_ERR "kzalloc error\n");
|
printk(KERN_ERR "kzalloc error\n");
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
|
if (i == ARRAY_SIZE(uvc_formats)) {
|
||||||
printk(KERN_INFO "Unsupported format 0x%08x.\n",
|
printk(KERN_INFO "Unsupported format 0x%08x.\n",
|
||||||
fmt->fmt.pix.pixelformat);
|
fmt->fmt.pix.pixelformat);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -829,6 +829,7 @@ static void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||||
* almost immediately. With ISP1761, this register requires a delay of
|
* almost immediately. With ISP1761, this register requires a delay of
|
||||||
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
||||||
*/
|
*/
|
||||||
|
mmiowb();
|
||||||
ndelay(195);
|
ndelay(195);
|
||||||
skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
|
skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
|
||||||
|
|
||||||
|
@ -870,6 +871,7 @@ static void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
|
||||||
* almost immediately. With ISP1761, this register requires a delay of
|
* almost immediately. With ISP1761, this register requires a delay of
|
||||||
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
* 195ns between a write and subsequent read (see section 15.1.1.3).
|
||||||
*/
|
*/
|
||||||
|
mmiowb();
|
||||||
ndelay(195);
|
ndelay(195);
|
||||||
skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
|
skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ static void next_trb(struct xhci_hcd *xhci,
|
||||||
*seg = (*seg)->next;
|
*seg = (*seg)->next;
|
||||||
*trb = ((*seg)->trbs);
|
*trb = ((*seg)->trbs);
|
||||||
} else {
|
} else {
|
||||||
*trb = (*trb)++;
|
(*trb)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1551,6 +1551,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
|
||||||
/* calc actual length */
|
/* calc actual length */
|
||||||
if (ep->skip) {
|
if (ep->skip) {
|
||||||
td->urb->iso_frame_desc[idx].actual_length = 0;
|
td->urb->iso_frame_desc[idx].actual_length = 0;
|
||||||
|
/* Update ring dequeue pointer */
|
||||||
|
while (ep_ring->dequeue != td->last_trb)
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
|
inc_deq(xhci, ep_ring, false);
|
||||||
return finish_td(xhci, td, event_trb, event, ep, status, true);
|
return finish_td(xhci, td, event_trb, event, ep, status, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -439,7 +439,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
|
||||||
/* drain secondary buffer */
|
/* drain secondary buffer */
|
||||||
int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
|
int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
|
||||||
i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
|
i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
|
||||||
if (i < 0) {
|
if (i) {
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -542,7 +542,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
|
||||||
retval = io_res;
|
retval = io_res;
|
||||||
else {
|
else {
|
||||||
io_res = copy_to_user(user_buffer, buffer, dev->report_size);
|
io_res = copy_to_user(user_buffer, buffer, dev->report_size);
|
||||||
if (io_res < 0)
|
if (io_res)
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -574,7 +574,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
|
||||||
}
|
}
|
||||||
io_res = copy_to_user((struct iowarrior_info __user *)arg, &info,
|
io_res = copy_to_user((struct iowarrior_info __user *)arg, &info,
|
||||||
sizeof(struct iowarrior_info));
|
sizeof(struct iowarrior_info));
|
||||||
if (io_res < 0)
|
if (io_res)
|
||||||
retval = -EFAULT;
|
retval = -EFAULT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -550,6 +550,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
|
||||||
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
|
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
|
||||||
struct twl4030_usb *twl;
|
struct twl4030_usb *twl;
|
||||||
int status, err;
|
int status, err;
|
||||||
|
u8 pwr;
|
||||||
|
|
||||||
if (!pdata) {
|
if (!pdata) {
|
||||||
dev_dbg(&pdev->dev, "platform_data not available\n");
|
dev_dbg(&pdev->dev, "platform_data not available\n");
|
||||||
|
@ -568,7 +569,10 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
|
||||||
twl->otg.set_peripheral = twl4030_set_peripheral;
|
twl->otg.set_peripheral = twl4030_set_peripheral;
|
||||||
twl->otg.set_suspend = twl4030_set_suspend;
|
twl->otg.set_suspend = twl4030_set_suspend;
|
||||||
twl->usb_mode = pdata->usb_mode;
|
twl->usb_mode = pdata->usb_mode;
|
||||||
twl->asleep = 1;
|
|
||||||
|
pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
|
||||||
|
|
||||||
|
twl->asleep = (pwr & PHY_PWR_PHYPWD);
|
||||||
|
|
||||||
/* init spinlock for workqueue */
|
/* init spinlock for workqueue */
|
||||||
spin_lock_init(&twl->lock);
|
spin_lock_init(&twl->lock);
|
||||||
|
|
|
@ -222,8 +222,8 @@ static struct usb_serial_driver cp210x_device = {
|
||||||
#define BITS_STOP_2 0x0002
|
#define BITS_STOP_2 0x0002
|
||||||
|
|
||||||
/* CP210X_SET_BREAK */
|
/* CP210X_SET_BREAK */
|
||||||
#define BREAK_ON 0x0000
|
#define BREAK_ON 0x0001
|
||||||
#define BREAK_OFF 0x0001
|
#define BREAK_OFF 0x0000
|
||||||
|
|
||||||
/* CP210X_(SET_MHS|GET_MDMSTS) */
|
/* CP210X_(SET_MHS|GET_MDMSTS) */
|
||||||
#define CONTROL_DTR 0x0001
|
#define CONTROL_DTR 0x0001
|
||||||
|
|
|
@ -180,6 +180,7 @@ static struct usb_device_id id_table_combined [] = {
|
||||||
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
|
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
|
||||||
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
|
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
|
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
|
||||||
|
{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
|
||||||
{ USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
|
{ USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) },
|
||||||
|
@ -750,6 +751,8 @@ static struct usb_device_id id_table_combined [] = {
|
||||||
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID),
|
{ USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID),
|
||||||
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||||||
{ USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
|
{ USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) },
|
||||||
|
{ USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID),
|
||||||
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
||||||
{ }, /* Optional parameter entry */
|
{ }, /* Optional parameter entry */
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
|
@ -1376,7 +1379,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set max packet size based on descriptor */
|
/* set max packet size based on descriptor */
|
||||||
priv->max_packet_size = ep_desc->wMaxPacketSize;
|
priv->max_packet_size = le16_to_cpu(ep_desc->wMaxPacketSize);
|
||||||
|
|
||||||
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,9 @@
|
||||||
/* Propox devices */
|
/* Propox devices */
|
||||||
#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
|
#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738
|
||||||
|
|
||||||
|
/* Lenz LI-USB Computer Interface. */
|
||||||
|
#define FTDI_LENZ_LIUSB_PID 0xD780
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Xsens Technologies BV products (http://www.xsens.com).
|
* Xsens Technologies BV products (http://www.xsens.com).
|
||||||
*/
|
*/
|
||||||
|
@ -988,6 +991,12 @@
|
||||||
#define ALTI2_VID 0x1BC9
|
#define ALTI2_VID 0x1BC9
|
||||||
#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
|
#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ionics PlugComputer
|
||||||
|
*/
|
||||||
|
#define IONICS_VID 0x1c0c
|
||||||
|
#define IONICS_PLUGCOMPUTER_PID 0x0102
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dresden Elektronik Sensor Terminal Board
|
* Dresden Elektronik Sensor Terminal Board
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -518,6 +518,7 @@ void usb_serial_generic_disconnect(struct usb_serial *serial)
|
||||||
for (i = 0; i < serial->num_ports; ++i)
|
for (i = 0; i < serial->num_ports; ++i)
|
||||||
generic_cleanup(serial->port[i]);
|
generic_cleanup(serial->port[i]);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
|
||||||
|
|
||||||
void usb_serial_generic_release(struct usb_serial *serial)
|
void usb_serial_generic_release(struct usb_serial *serial)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1151,7 +1151,7 @@ static int download_fw(struct edgeport_serial *serial)
|
||||||
|
|
||||||
/* Check if we have an old version in the I2C and
|
/* Check if we have an old version in the I2C and
|
||||||
update if necessary */
|
update if necessary */
|
||||||
if (download_cur_ver != download_new_ver) {
|
if (download_cur_ver < download_new_ver) {
|
||||||
dbg("%s - Update I2C dld from %d.%d to %d.%d",
|
dbg("%s - Update I2C dld from %d.%d to %d.%d",
|
||||||
__func__,
|
__func__,
|
||||||
firmware_version->Ver_Major,
|
firmware_version->Ver_Major,
|
||||||
|
@ -1284,7 +1284,7 @@ static int download_fw(struct edgeport_serial *serial)
|
||||||
kfree(header);
|
kfree(header);
|
||||||
kfree(rom_desc);
|
kfree(rom_desc);
|
||||||
kfree(ti_manuf_desc);
|
kfree(ti_manuf_desc);
|
||||||
return status;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update I2C with type 0xf2 record with correct
|
/* Update I2C with type 0xf2 record with correct
|
||||||
|
|
|
@ -25,6 +25,7 @@ static int debug;
|
||||||
|
|
||||||
static const struct usb_device_id id_table[] = {
|
static const struct usb_device_id id_table[] = {
|
||||||
{ USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
|
{ USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
|
||||||
|
{ USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, id_table);
|
MODULE_DEVICE_TABLE(usb, id_table);
|
||||||
|
|
|
@ -365,6 +365,10 @@ static void option_instat_callback(struct urb *urb);
|
||||||
#define OLIVETTI_VENDOR_ID 0x0b3c
|
#define OLIVETTI_VENDOR_ID 0x0b3c
|
||||||
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
|
#define OLIVETTI_PRODUCT_OLICARD100 0xc000
|
||||||
|
|
||||||
|
/* Celot products */
|
||||||
|
#define CELOT_VENDOR_ID 0x211f
|
||||||
|
#define CELOT_PRODUCT_CT680M 0x6801
|
||||||
|
|
||||||
/* some devices interfaces need special handling due to a number of reasons */
|
/* some devices interfaces need special handling due to a number of reasons */
|
||||||
enum option_blacklist_reason {
|
enum option_blacklist_reason {
|
||||||
OPTION_BLACKLIST_NONE = 0,
|
OPTION_BLACKLIST_NONE = 0,
|
||||||
|
@ -887,10 +891,9 @@ static const struct usb_device_id option_ids[] = {
|
||||||
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) },
|
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) },
|
||||||
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)},
|
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)},
|
||||||
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
|
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
|
||||||
|
|
||||||
{ USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
|
{ USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
|
||||||
|
|
||||||
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
|
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
|
||||||
|
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
|
||||||
{ } /* Terminating entry */
|
{ } /* Terminating entry */
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(usb, option_ids);
|
MODULE_DEVICE_TABLE(usb, option_ids);
|
||||||
|
|
|
@ -86,6 +86,7 @@ static const struct usb_device_id id_table[] = {
|
||||||
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
|
{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
|
||||||
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
|
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
|
||||||
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
|
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
|
||||||
|
{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },
|
||||||
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
|
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
|
||||||
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
|
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
|
||||||
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
|
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
|
||||||
|
|
|
@ -128,6 +128,10 @@
|
||||||
#define CRESSI_VENDOR_ID 0x04b8
|
#define CRESSI_VENDOR_ID 0x04b8
|
||||||
#define CRESSI_EDY_PRODUCT_ID 0x0521
|
#define CRESSI_EDY_PRODUCT_ID 0x0521
|
||||||
|
|
||||||
|
/* Zeagle dive computer interface */
|
||||||
|
#define ZEAGLE_VENDOR_ID 0x04b8
|
||||||
|
#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522
|
||||||
|
|
||||||
/* Sony, USB data cable for CMD-Jxx mobile phones */
|
/* Sony, USB data cable for CMD-Jxx mobile phones */
|
||||||
#define SONY_VENDOR_ID 0x054c
|
#define SONY_VENDOR_ID 0x054c
|
||||||
#define SONY_QN3USB_PRODUCT_ID 0x0437
|
#define SONY_QN3USB_PRODUCT_ID 0x0437
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/usb/serial.h>
|
#include <linux/usb/serial.h>
|
||||||
|
#include <linux/serial_reg.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#define QT_OPEN_CLOSE_CHANNEL 0xca
|
#define QT_OPEN_CLOSE_CHANNEL 0xca
|
||||||
|
@ -27,36 +28,11 @@
|
||||||
#define QT_HW_FLOW_CONTROL_MASK 0xc5
|
#define QT_HW_FLOW_CONTROL_MASK 0xc5
|
||||||
#define QT_SW_FLOW_CONTROL_MASK 0xc6
|
#define QT_SW_FLOW_CONTROL_MASK 0xc6
|
||||||
|
|
||||||
#define MODEM_CTL_REGISTER 0x04
|
|
||||||
#define MODEM_STATUS_REGISTER 0x06
|
|
||||||
|
|
||||||
|
|
||||||
#define SERIAL_LSR_OE 0x02
|
|
||||||
#define SERIAL_LSR_PE 0x04
|
|
||||||
#define SERIAL_LSR_FE 0x08
|
|
||||||
#define SERIAL_LSR_BI 0x10
|
|
||||||
|
|
||||||
#define SERIAL_LSR_TEMT 0x40
|
|
||||||
|
|
||||||
#define SERIAL_MCR_DTR 0x01
|
|
||||||
#define SERIAL_MCR_RTS 0x02
|
|
||||||
#define SERIAL_MCR_LOOP 0x10
|
|
||||||
|
|
||||||
#define SERIAL_MSR_CTS 0x10
|
|
||||||
#define SERIAL_MSR_CD 0x80
|
|
||||||
#define SERIAL_MSR_RI 0x40
|
|
||||||
#define SERIAL_MSR_DSR 0x20
|
|
||||||
#define SERIAL_MSR_MASK 0xf0
|
#define SERIAL_MSR_MASK 0xf0
|
||||||
|
|
||||||
#define SERIAL_CRTSCTS ((SERIAL_MCR_RTS << 8) | SERIAL_MSR_CTS)
|
#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
|
||||||
|
|
||||||
#define SERIAL_8_DATA 0x03
|
#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
|
||||||
#define SERIAL_7_DATA 0x02
|
|
||||||
#define SERIAL_6_DATA 0x01
|
|
||||||
#define SERIAL_5_DATA 0x00
|
|
||||||
|
|
||||||
#define SERIAL_ODD_PARITY 0X08
|
|
||||||
#define SERIAL_EVEN_PARITY 0X18
|
|
||||||
|
|
||||||
#define MAX_BAUD_RATE 460800
|
#define MAX_BAUD_RATE 460800
|
||||||
|
|
||||||
|
@ -99,10 +75,12 @@ static struct usb_driver ssu100_driver = {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssu100_port_private {
|
struct ssu100_port_private {
|
||||||
|
spinlock_t status_lock;
|
||||||
u8 shadowLSR;
|
u8 shadowLSR;
|
||||||
u8 shadowMSR;
|
u8 shadowMSR;
|
||||||
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
||||||
unsigned short max_packet_size;
|
unsigned short max_packet_size;
|
||||||
|
struct async_icount icount;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ssu100_release(struct usb_serial *serial)
|
static void ssu100_release(struct usb_serial *serial)
|
||||||
|
@ -150,9 +128,10 @@ static inline int ssu100_getregister(struct usb_device *dev,
|
||||||
|
|
||||||
static inline int ssu100_setregister(struct usb_device *dev,
|
static inline int ssu100_setregister(struct usb_device *dev,
|
||||||
unsigned short uart,
|
unsigned short uart,
|
||||||
|
unsigned short reg,
|
||||||
u16 data)
|
u16 data)
|
||||||
{
|
{
|
||||||
u16 value = (data << 8) | MODEM_CTL_REGISTER;
|
u16 value = (data << 8) | reg;
|
||||||
|
|
||||||
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||||
QT_SET_GET_REGISTER, 0x40, value, uart,
|
QT_SET_GET_REGISTER, 0x40, value, uart,
|
||||||
|
@ -178,11 +157,11 @@ static inline int update_mctrl(struct usb_device *dev, unsigned int set,
|
||||||
clear &= ~set; /* 'set' takes precedence over 'clear' */
|
clear &= ~set; /* 'set' takes precedence over 'clear' */
|
||||||
urb_value = 0;
|
urb_value = 0;
|
||||||
if (set & TIOCM_DTR)
|
if (set & TIOCM_DTR)
|
||||||
urb_value |= SERIAL_MCR_DTR;
|
urb_value |= UART_MCR_DTR;
|
||||||
if (set & TIOCM_RTS)
|
if (set & TIOCM_RTS)
|
||||||
urb_value |= SERIAL_MCR_RTS;
|
urb_value |= UART_MCR_RTS;
|
||||||
|
|
||||||
result = ssu100_setregister(dev, 0, urb_value);
|
result = ssu100_setregister(dev, 0, UART_MCR, urb_value);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
dbg("%s Error from MODEM_CTRL urb", __func__);
|
dbg("%s Error from MODEM_CTRL urb", __func__);
|
||||||
|
|
||||||
|
@ -264,24 +243,24 @@ static void ssu100_set_termios(struct tty_struct *tty,
|
||||||
|
|
||||||
if (cflag & PARENB) {
|
if (cflag & PARENB) {
|
||||||
if (cflag & PARODD)
|
if (cflag & PARODD)
|
||||||
urb_value |= SERIAL_ODD_PARITY;
|
urb_value |= UART_LCR_PARITY;
|
||||||
else
|
else
|
||||||
urb_value |= SERIAL_EVEN_PARITY;
|
urb_value |= SERIAL_EVEN_PARITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cflag & CSIZE) {
|
switch (cflag & CSIZE) {
|
||||||
case CS5:
|
case CS5:
|
||||||
urb_value |= SERIAL_5_DATA;
|
urb_value |= UART_LCR_WLEN5;
|
||||||
break;
|
break;
|
||||||
case CS6:
|
case CS6:
|
||||||
urb_value |= SERIAL_6_DATA;
|
urb_value |= UART_LCR_WLEN6;
|
||||||
break;
|
break;
|
||||||
case CS7:
|
case CS7:
|
||||||
urb_value |= SERIAL_7_DATA;
|
urb_value |= UART_LCR_WLEN7;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case CS8:
|
case CS8:
|
||||||
urb_value |= SERIAL_8_DATA;
|
urb_value |= UART_LCR_WLEN8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +312,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||||
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
||||||
u8 *data;
|
u8 *data;
|
||||||
int result;
|
int result;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
dbg("%s - port %d", __func__, port->number);
|
dbg("%s - port %d", __func__, port->number);
|
||||||
|
|
||||||
|
@ -350,11 +330,10 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE |
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
SERIAL_LSR_FE | SERIAL_LSR_BI);
|
priv->shadowLSR = data[0];
|
||||||
|
priv->shadowMSR = data[1];
|
||||||
priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
SERIAL_MSR_RI | SERIAL_MSR_CD);
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
|
@ -398,11 +377,51 @@ static int get_serial_info(struct usb_serial_port *port,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
|
||||||
|
{
|
||||||
|
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
||||||
|
struct async_icount prev, cur;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
prev = priv->icount;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
wait_event_interruptible(priv->delta_msr_wait,
|
||||||
|
((priv->icount.rng != prev.rng) ||
|
||||||
|
(priv->icount.dsr != prev.dsr) ||
|
||||||
|
(priv->icount.dcd != prev.dcd) ||
|
||||||
|
(priv->icount.cts != prev.cts)));
|
||||||
|
|
||||||
|
if (signal_pending(current))
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
cur = priv->icount;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
if ((prev.rng == cur.rng) &&
|
||||||
|
(prev.dsr == cur.dsr) &&
|
||||||
|
(prev.dcd == cur.dcd) &&
|
||||||
|
(prev.cts == cur.cts))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
|
||||||
|
(arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
|
||||||
|
(arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
|
||||||
|
(arg & TIOCM_CTS && (prev.cts != cur.cts)))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
|
static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct usb_serial_port *port = tty->driver_data;
|
struct usb_serial_port *port = tty->driver_data;
|
||||||
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
||||||
|
void __user *user_arg = (void __user *)arg;
|
||||||
|
|
||||||
dbg("%s cmd 0x%04x", __func__, cmd);
|
dbg("%s cmd 0x%04x", __func__, cmd);
|
||||||
|
|
||||||
|
@ -412,28 +431,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
|
||||||
(struct serial_struct __user *) arg);
|
(struct serial_struct __user *) arg);
|
||||||
|
|
||||||
case TIOCMIWAIT:
|
case TIOCMIWAIT:
|
||||||
while (priv != NULL) {
|
return wait_modem_info(port, arg);
|
||||||
u8 prevMSR = priv->shadowMSR & SERIAL_MSR_MASK;
|
|
||||||
interruptible_sleep_on(&priv->delta_msr_wait);
|
|
||||||
/* see if a signal did it */
|
|
||||||
if (signal_pending(current))
|
|
||||||
return -ERESTARTSYS;
|
|
||||||
else {
|
|
||||||
u8 diff = (priv->shadowMSR & SERIAL_MSR_MASK) ^ prevMSR;
|
|
||||||
if (!diff)
|
|
||||||
return -EIO; /* no change => error */
|
|
||||||
|
|
||||||
/* Return 0 if caller wanted to know about
|
case TIOCGICOUNT:
|
||||||
these bits */
|
{
|
||||||
|
struct serial_icounter_struct icount;
|
||||||
if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) ||
|
struct async_icount cnow = priv->icount;
|
||||||
((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) ||
|
memset(&icount, 0, sizeof(icount));
|
||||||
((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) ||
|
icount.cts = cnow.cts;
|
||||||
((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS)))
|
icount.dsr = cnow.dsr;
|
||||||
return 0;
|
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;
|
||||||
|
if (copy_to_user(user_arg, &icount, sizeof(icount)))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -455,6 +474,7 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port)
|
||||||
|
|
||||||
unsigned num_endpoints;
|
unsigned num_endpoints;
|
||||||
int i;
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
|
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
|
||||||
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
|
dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
|
||||||
|
@ -466,7 +486,9 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set max packet size based on descriptor */
|
/* set max packet size based on descriptor */
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
priv->max_packet_size = ep_desc->wMaxPacketSize;
|
priv->max_packet_size = ep_desc->wMaxPacketSize;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
|
||||||
}
|
}
|
||||||
|
@ -485,9 +507,9 @@ static int ssu100_attach(struct usb_serial *serial)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&priv->status_lock);
|
||||||
init_waitqueue_head(&priv->delta_msr_wait);
|
init_waitqueue_head(&priv->delta_msr_wait);
|
||||||
usb_set_serial_port_data(port, priv);
|
usb_set_serial_port_data(port, priv);
|
||||||
|
|
||||||
ssu100_set_max_packet_size(port);
|
ssu100_set_max_packet_size(port);
|
||||||
|
|
||||||
return ssu100_initdevice(serial->dev);
|
return ssu100_initdevice(serial->dev);
|
||||||
|
@ -506,20 +528,20 @@ static int ssu100_tiocmget(struct tty_struct *tty, struct file *file)
|
||||||
if (!d)
|
if (!d)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d);
|
r = ssu100_getregister(dev, 0, UART_MCR, d);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto mget_out;
|
goto mget_out;
|
||||||
|
|
||||||
r = ssu100_getregister(dev, 0, MODEM_STATUS_REGISTER, d+1);
|
r = ssu100_getregister(dev, 0, UART_MSR, d+1);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto mget_out;
|
goto mget_out;
|
||||||
|
|
||||||
r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) |
|
r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
|
||||||
(d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) |
|
(d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
|
||||||
(d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) |
|
(d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
|
||||||
(d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) |
|
(d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
|
||||||
(d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) |
|
(d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
|
||||||
(d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0);
|
(d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
|
||||||
|
|
||||||
mget_out:
|
mget_out:
|
||||||
kfree(d);
|
kfree(d);
|
||||||
|
@ -546,7 +568,7 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
|
||||||
if (!port->serial->disconnected) {
|
if (!port->serial->disconnected) {
|
||||||
/* Disable flow control */
|
/* Disable flow control */
|
||||||
if (!on &&
|
if (!on &&
|
||||||
ssu100_setregister(dev, 0, 0) < 0)
|
ssu100_setregister(dev, 0, UART_MCR, 0) < 0)
|
||||||
dev_err(&port->dev, "error from flowcontrol urb\n");
|
dev_err(&port->dev, "error from flowcontrol urb\n");
|
||||||
/* drop RTS and DTR */
|
/* drop RTS and DTR */
|
||||||
if (on)
|
if (on)
|
||||||
|
@ -557,34 +579,88 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
|
||||||
mutex_unlock(&port->serial->disc_mutex);
|
mutex_unlock(&port->serial->disc_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)
|
||||||
|
{
|
||||||
|
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
priv->shadowMSR = msr;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
if (msr & UART_MSR_ANY_DELTA) {
|
||||||
|
/* update input line counters */
|
||||||
|
if (msr & UART_MSR_DCTS)
|
||||||
|
priv->icount.cts++;
|
||||||
|
if (msr & UART_MSR_DDSR)
|
||||||
|
priv->icount.dsr++;
|
||||||
|
if (msr & UART_MSR_DDCD)
|
||||||
|
priv->icount.dcd++;
|
||||||
|
if (msr & UART_MSR_TERI)
|
||||||
|
priv->icount.rng++;
|
||||||
|
wake_up_interruptible(&priv->delta_msr_wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,
|
||||||
|
char *tty_flag)
|
||||||
|
{
|
||||||
|
struct ssu100_port_private *priv = usb_get_serial_port_data(port);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&priv->status_lock, flags);
|
||||||
|
priv->shadowLSR = lsr;
|
||||||
|
spin_unlock_irqrestore(&priv->status_lock, flags);
|
||||||
|
|
||||||
|
*tty_flag = TTY_NORMAL;
|
||||||
|
if (lsr & UART_LSR_BRK_ERROR_BITS) {
|
||||||
|
/* we always want to update icount, but we only want to
|
||||||
|
* update tty_flag for one case */
|
||||||
|
if (lsr & UART_LSR_BI) {
|
||||||
|
priv->icount.brk++;
|
||||||
|
*tty_flag = TTY_BREAK;
|
||||||
|
usb_serial_handle_break(port);
|
||||||
|
}
|
||||||
|
if (lsr & UART_LSR_PE) {
|
||||||
|
priv->icount.parity++;
|
||||||
|
if (*tty_flag == TTY_NORMAL)
|
||||||
|
*tty_flag = TTY_PARITY;
|
||||||
|
}
|
||||||
|
if (lsr & UART_LSR_FE) {
|
||||||
|
priv->icount.frame++;
|
||||||
|
if (*tty_flag == TTY_NORMAL)
|
||||||
|
*tty_flag = TTY_FRAME;
|
||||||
|
}
|
||||||
|
if (lsr & UART_LSR_OE){
|
||||||
|
priv->icount.overrun++;
|
||||||
|
if (*tty_flag == TTY_NORMAL)
|
||||||
|
*tty_flag = TTY_OVERRUN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static int ssu100_process_packet(struct tty_struct *tty,
|
static int ssu100_process_packet(struct tty_struct *tty,
|
||||||
struct usb_serial_port *port,
|
struct usb_serial_port *port,
|
||||||
struct ssu100_port_private *priv,
|
struct ssu100_port_private *priv,
|
||||||
char *packet, int len)
|
char *packet, int len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char flag;
|
char flag = TTY_NORMAL;
|
||||||
char *ch;
|
char *ch;
|
||||||
|
|
||||||
dbg("%s - port %d", __func__, port->number);
|
dbg("%s - port %d", __func__, port->number);
|
||||||
|
|
||||||
if (len < 4) {
|
if ((len >= 4) &&
|
||||||
dbg("%s - malformed packet", __func__);
|
(packet[0] == 0x1b) && (packet[1] == 0x1b) &&
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((packet[0] == 0x1b) && (packet[1] == 0x1b) &&
|
|
||||||
((packet[2] == 0x00) || (packet[2] == 0x01))) {
|
((packet[2] == 0x00) || (packet[2] == 0x01))) {
|
||||||
if (packet[2] == 0x00)
|
if (packet[2] == 0x00) {
|
||||||
priv->shadowLSR = packet[3] & (SERIAL_LSR_OE |
|
ssu100_update_lsr(port, packet[3], &flag);
|
||||||
SERIAL_LSR_PE |
|
if (flag == TTY_OVERRUN)
|
||||||
SERIAL_LSR_FE |
|
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||||
SERIAL_LSR_BI);
|
|
||||||
|
|
||||||
if (packet[2] == 0x01) {
|
|
||||||
priv->shadowMSR = packet[3];
|
|
||||||
wake_up_interruptible(&priv->delta_msr_wait);
|
|
||||||
}
|
}
|
||||||
|
if (packet[2] == 0x01)
|
||||||
|
ssu100_update_msr(port, packet[3]);
|
||||||
|
|
||||||
len -= 4;
|
len -= 4;
|
||||||
ch = packet + 4;
|
ch = packet + 4;
|
||||||
|
@ -631,7 +707,6 @@ static void ssu100_process_read_urb(struct urb *urb)
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct usb_serial_driver ssu100_device = {
|
static struct usb_serial_driver ssu100_device = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
@ -653,6 +728,7 @@ static struct usb_serial_driver ssu100_device = {
|
||||||
.tiocmset = ssu100_tiocmset,
|
.tiocmset = ssu100_tiocmset,
|
||||||
.ioctl = ssu100_ioctl,
|
.ioctl = ssu100_ioctl,
|
||||||
.set_termios = ssu100_set_termios,
|
.set_termios = ssu100_set_termios,
|
||||||
|
.disconnect = usb_serial_generic_disconnect,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ssu100_init(void)
|
static int __init ssu100_init(void)
|
||||||
|
|
|
@ -736,6 +736,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
serial = create_serial(dev, interface, type);
|
serial = create_serial(dev, interface, type);
|
||||||
if (!serial) {
|
if (!serial) {
|
||||||
|
module_put(type->driver.owner);
|
||||||
dev_err(&interface->dev, "%s - out of memory\n", __func__);
|
dev_err(&interface->dev, "%s - out of memory\n", __func__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -746,11 +747,11 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
id = get_iface_id(type, interface);
|
id = get_iface_id(type, interface);
|
||||||
retval = type->probe(serial, id);
|
retval = type->probe(serial, id);
|
||||||
module_put(type->driver.owner);
|
|
||||||
|
|
||||||
if (retval) {
|
if (retval) {
|
||||||
dbg("sub driver rejected device");
|
dbg("sub driver rejected device");
|
||||||
kfree(serial);
|
kfree(serial);
|
||||||
|
module_put(type->driver.owner);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -822,6 +823,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
if (num_bulk_in == 0 || num_bulk_out == 0) {
|
||||||
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
|
||||||
kfree(serial);
|
kfree(serial);
|
||||||
|
module_put(type->driver.owner);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -835,22 +837,15 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
dev_err(&interface->dev,
|
dev_err(&interface->dev,
|
||||||
"Generic device with no bulk out, not allowed.\n");
|
"Generic device with no bulk out, not allowed.\n");
|
||||||
kfree(serial);
|
kfree(serial);
|
||||||
|
module_put(type->driver.owner);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!num_ports) {
|
if (!num_ports) {
|
||||||
/* if this device type has a calc_num_ports function, call it */
|
/* if this device type has a calc_num_ports function, call it */
|
||||||
if (type->calc_num_ports) {
|
if (type->calc_num_ports)
|
||||||
if (!try_module_get(type->driver.owner)) {
|
|
||||||
dev_err(&interface->dev,
|
|
||||||
"module get failed, exiting\n");
|
|
||||||
kfree(serial);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
num_ports = type->calc_num_ports(serial);
|
num_ports = type->calc_num_ports(serial);
|
||||||
module_put(type->driver.owner);
|
|
||||||
}
|
|
||||||
if (!num_ports)
|
if (!num_ports)
|
||||||
num_ports = type->num_ports;
|
num_ports = type->num_ports;
|
||||||
}
|
}
|
||||||
|
@ -1039,13 +1034,7 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
/* if this device type has an attach function, call it */
|
/* if this device type has an attach function, call it */
|
||||||
if (type->attach) {
|
if (type->attach) {
|
||||||
if (!try_module_get(type->driver.owner)) {
|
|
||||||
dev_err(&interface->dev,
|
|
||||||
"module get failed, exiting\n");
|
|
||||||
goto probe_error;
|
|
||||||
}
|
|
||||||
retval = type->attach(serial);
|
retval = type->attach(serial);
|
||||||
module_put(type->driver.owner);
|
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
goto probe_error;
|
goto probe_error;
|
||||||
serial->attached = 1;
|
serial->attached = 1;
|
||||||
|
@ -1088,10 +1077,12 @@ int usb_serial_probe(struct usb_interface *interface,
|
||||||
exit:
|
exit:
|
||||||
/* success */
|
/* success */
|
||||||
usb_set_intfdata(interface, serial);
|
usb_set_intfdata(interface, serial);
|
||||||
|
module_put(type->driver.owner);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
probe_error:
|
probe_error:
|
||||||
usb_serial_put(serial);
|
usb_serial_put(serial);
|
||||||
|
module_put(type->driver.owner);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_serial_probe);
|
EXPORT_SYMBOL_GPL(usb_serial_probe);
|
||||||
|
|
|
@ -247,6 +247,7 @@ int usb_add_config(struct usb_composite_dev *,
|
||||||
* value; it should return zero on successful initialization.
|
* value; it should return zero on successful initialization.
|
||||||
* @unbind: Reverses @bind(); called as a side effect of unregistering
|
* @unbind: Reverses @bind(); called as a side effect of unregistering
|
||||||
* this driver.
|
* this driver.
|
||||||
|
* @disconnect: optional driver disconnect method
|
||||||
* @suspend: Notifies when the host stops sending USB traffic,
|
* @suspend: Notifies when the host stops sending USB traffic,
|
||||||
* after function notifications
|
* after function notifications
|
||||||
* @resume: Notifies configuration when the host restarts USB traffic,
|
* @resume: Notifies configuration when the host restarts USB traffic,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче