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:
Linus Torvalds 2010-08-24 00:20:44 -07:00
Родитель d1b113bb02 70ddd47f7d
Коммит d20de76354
25 изменённых файлов: 227 добавлений и 125 удалений

Просмотреть файл

@ -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;
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;
} }
}
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,