Commit d20de763 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents d1b113bb 70ddd47f
......@@ -279,13 +279,13 @@ static void __init eukrea_cpuimx27_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
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);
}
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);
#endif
......
......@@ -419,13 +419,13 @@ static void __init pca100_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
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);
}
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);
#endif
......
......@@ -138,7 +138,7 @@ static void __init eukrea_cpuimx25_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
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);
}
......
......@@ -192,7 +192,7 @@ static void __init mxc_board_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
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);
}
......
......@@ -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
* @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
* Context: single threaded during gadget setup
*
* 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.
*
* @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 */
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
if (m66592 == NULL) {
ret = -ENOMEM;
pr_err("kzalloc error\n");
goto clean_up;
}
......
......@@ -1557,6 +1557,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
/* initialize ucd */
r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);
if (r8a66597 == NULL) {
ret = -ENOMEM;
printk(KERN_ERR "kzalloc error\n");
goto clean_up;
}
......
......@@ -94,7 +94,7 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
break;
}
if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
if (i == ARRAY_SIZE(uvc_formats)) {
printk(KERN_INFO "Unsupported format 0x%08x.\n",
fmt->fmt.pix.pixelformat);
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
* 195ns between a write and subsequent read (see section 15.1.1.3).
*/
mmiowb();
ndelay(195);
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
* 195ns between a write and subsequent read (see section 15.1.1.3).
*/
mmiowb();
ndelay(195);
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;
*trb = ((*seg)->trbs);
} else {
*trb = (*trb)++;
(*trb)++;
}
}
......@@ -1551,6 +1551,10 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* calc actual length */
if (ep->skip) {
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);
}
......
......@@ -439,7 +439,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
/* drain secondary buffer */
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);
if (i < 0) {
if (i) {
retval = -EFAULT;
goto exit;
}
......
......@@ -542,7 +542,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
retval = io_res;
else {
io_res = copy_to_user(user_buffer, buffer, dev->report_size);
if (io_res < 0)
if (io_res)
retval = -EFAULT;
}
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,
sizeof(struct iowarrior_info));
if (io_res < 0)
if (io_res)
retval = -EFAULT;
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 *twl;
int status, err;
u8 pwr;
if (!pdata) {
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_suspend = twl4030_set_suspend;
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 */
spin_lock_init(&twl->lock);
......
......@@ -222,8 +222,8 @@ static struct usb_serial_driver cp210x_device = {
#define BITS_STOP_2 0x0002
/* CP210X_SET_BREAK */
#define BREAK_ON 0x0000
#define BREAK_OFF 0x0001
#define BREAK_ON 0x0001
#define BREAK_OFF 0x0000
/* CP210X_(SET_MHS|GET_MDMSTS) */
#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_MINI_IOBOARD_PID) },
{ 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_634_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),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ 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 */
{ } /* 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 */
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);
}
......
......@@ -110,6 +110,9 @@
/* Propox devices */
#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).
*/
......@@ -988,6 +991,12 @@
#define ALTI2_VID 0x1BC9
#define ALTI2_N3_PID 0x6001 /* Neptune 3 */
/*
* Ionics PlugComputer
*/
#define IONICS_VID 0x1c0c
#define IONICS_PLUGCOMPUTER_PID 0x0102
/*
* 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)
generic_cleanup(serial->port[i]);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
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
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",
__func__,
firmware_version->Ver_Major,
......@@ -1284,7 +1284,7 @@ static int download_fw(struct edgeport_serial *serial)
kfree(header);
kfree(rom_desc);
kfree(ti_manuf_desc);
return status;
return -EINVAL;
}
/* Update I2C with type 0xf2 record with correct
......
......@@ -25,6 +25,7 @@ static int debug;
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
{ USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */
{ },
};
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_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 */
enum option_blacklist_reason {
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_1011)},
{ USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)},
{ USB_DEVICE(CINTERION_VENDOR_ID, 0x0047) },
{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) },
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ } /* Terminating entry */
};
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(HP_VENDOR_ID, HP_LD220_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(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
{ USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
......
......@@ -128,6 +128,10 @@
#define CRESSI_VENDOR_ID 0x04b8
#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 */
#define SONY_VENDOR_ID 0x054c
#define SONY_QN3USB_PRODUCT_ID 0x0437
......
......@@ -15,6 +15,7 @@
#include <linux/serial.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial_reg.h>
#include <linux/uaccess.h>
#define QT_OPEN_CLOSE_CHANNEL 0xca
......@@ -27,36 +28,11 @@
#define QT_HW_FLOW_CONTROL_MASK 0xc5
#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_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_7_DATA 0x02
#define SERIAL_6_DATA 0x01
#define SERIAL_5_DATA 0x00
#define SERIAL_ODD_PARITY 0X08
#define SERIAL_EVEN_PARITY 0X18
#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
#define MAX_BAUD_RATE 460800
......@@ -99,10 +75,12 @@ static struct usb_driver ssu100_driver = {
};
struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
u8 shadowMSR;
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
unsigned short max_packet_size;
struct async_icount icount;
};
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,
unsigned short uart,
unsigned short reg,
u16 data)
{
u16 value = (data << 8) | MODEM_CTL_REGISTER;
u16 value = (data << 8) | reg;
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
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' */
urb_value = 0;
if (set & TIOCM_DTR)
urb_value |= SERIAL_MCR_DTR;
urb_value |= UART_MCR_DTR;
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)
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 & PARODD)
urb_value |= SERIAL_ODD_PARITY;
urb_value |= UART_LCR_PARITY;
else
urb_value |= SERIAL_EVEN_PARITY;
}
switch (cflag & CSIZE) {
case CS5:
urb_value |= SERIAL_5_DATA;
urb_value |= UART_LCR_WLEN5;
break;
case CS6:
urb_value |= SERIAL_6_DATA;
urb_value |= UART_LCR_WLEN6;
break;
case CS7:
urb_value |= SERIAL_7_DATA;
urb_value |= UART_LCR_WLEN7;
break;
default:
case CS8:
urb_value |= SERIAL_8_DATA;
urb_value |= UART_LCR_WLEN8;
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);
u8 *data;
int result;
unsigned long flags;
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;
}
priv->shadowLSR = data[0] & (SERIAL_LSR_OE | SERIAL_LSR_PE |
SERIAL_LSR_FE | SERIAL_LSR_BI);
priv->shadowMSR = data[1] & (SERIAL_MSR_CTS | SERIAL_MSR_DSR |
SERIAL_MSR_RI | SERIAL_MSR_CD);
spin_lock_irqsave(&priv->status_lock, flags);
priv->shadowLSR = data[0];
priv->shadowMSR = data[1];
spin_unlock_irqrestore(&priv->status_lock, flags);
kfree(data);
......@@ -398,11 +377,51 @@ static int get_serial_info(struct usb_serial_port *port,
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,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
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);
......@@ -412,28 +431,28 @@ static int ssu100_ioctl(struct tty_struct *tty, struct file *file,
(struct serial_struct __user *) arg);
case TIOCMIWAIT:
while (priv != NULL) {
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
these bits */
if (((arg & TIOCM_RNG) && (diff & SERIAL_MSR_RI)) ||
((arg & TIOCM_DSR) && (diff & SERIAL_MSR_DSR)) ||
((arg & TIOCM_CD) && (diff & SERIAL_MSR_CD)) ||
((arg & TIOCM_CTS) && (diff & SERIAL_MSR_CTS)))
return 0;
}
}
return wait_modem_info(port, arg);
case TIOCGICOUNT:
{
struct serial_icounter_struct icount;
struct async_icount cnow = priv->icount;
memset(&icount, 0, sizeof(icount));
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;
if (copy_to_user(user_arg, &icount, sizeof(icount)))
return -EFAULT;
return 0;
}
default:
break;
......@@ -455,6 +474,7 @@ static void ssu100_set_max_packet_size(struct usb_serial_port *port)
unsigned num_endpoints;
int i;
unsigned long flags;
num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
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 */
spin_lock_irqsave(&priv->status_lock, flags);
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);
}
......@@ -485,9 +507,9 @@ static int ssu100_attach(struct usb_serial *serial)
return -ENOMEM;
}
spin_lock_init(&priv->status_lock);
init_waitqueue_head(&priv->delta_msr_wait);
usb_set_serial_port_data(port, priv);
ssu100_set_max_packet_size(port);
return ssu100_initdevice(serial->dev);
......@@ -506,20 +528,20 @@ static int ssu100_tiocmget(struct tty_struct *tty, struct file *file)
if (!d)
return -ENOMEM;
r = ssu100_getregister(dev, 0, MODEM_CTL_REGISTER, d);
r = ssu100_getregister(dev, 0, UART_MCR, d);
if (r < 0)
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)
goto mget_out;
r = (d[0] & SERIAL_MCR_DTR ? TIOCM_DTR : 0) |
(d[0] & SERIAL_MCR_RTS ? TIOCM_RTS : 0) |
(d[1] & SERIAL_MSR_CTS ? TIOCM_CTS : 0) |
(d[1] & SERIAL_MSR_CD ? TIOCM_CAR : 0) |
(d[1] & SERIAL_MSR_RI ? TIOCM_RI : 0) |
(d[1] & SERIAL_MSR_DSR ? TIOCM_DSR : 0);
r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
(d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
(d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
(d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
(d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
(d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
mget_out:
kfree(d);
......@@ -546,7 +568,7 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
if (!port->serial->disconnected) {
/* Disable flow control */
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");
/* drop RTS and DTR */
if (on)
......@@ -557,34 +579,88 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
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,
struct usb_serial_port *port,
struct ssu100_port_private *priv,
char *packet, int len)
{
int i;
char flag;
char flag = TTY_NORMAL;
char *ch;
dbg("%s - port %d", __func__, port->number);
if (len < 4) {
dbg("%s - malformed packet", __func__);
return 0;
}
if ((packet[0] == 0x1b) && (packet[1] == 0x1b) &&
if ((len >= 4) &&
(packet[0] == 0x1b) && (packet[1] == 0x1b) &&
((packet[2] == 0x00) || (packet[2] == 0x01))) {
if (packet[2] == 0x00)
priv->shadowLSR = packet[3] & (SERIAL_LSR_OE |
SERIAL_LSR_PE |
SERIAL_LSR_FE |
SERIAL_LSR_BI);
if (packet[2] == 0x01) {
priv->shadowMSR = packet[3];
wake_up_interruptible(&priv->delta_msr_wait);
if (packet[2] == 0x00) {
ssu100_update_lsr(port, packet[3], &flag);
if (flag == TTY_OVERRUN)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
if (packet[2] == 0x01)
ssu100_update_msr(port, packet[3]);
len -= 4;
ch = packet + 4;
......@@ -631,7 +707,6 @@ static void ssu100_process_read_urb(struct urb *urb)
tty_kref_put(tty);
}
static struct usb_serial_driver ssu100_device = {
.driver = {
.owner = THIS_MODULE,
......@@ -653,6 +728,7 @@ static struct usb_serial_driver ssu100_device = {
.tiocmset = ssu100_tiocmset,
.ioctl = ssu100_ioctl,
.set_termios = ssu100_set_termios,
.disconnect = usb_serial_generic_disconnect,
};
static int __init ssu100_init(void)
......
......@@ -736,6 +736,7 @@ int usb_serial_probe(struct usb_interface *interface,
serial = create_serial(dev, interface, type);
if (!serial) {
module_put(type->driver.owner);
dev_err(&interface->dev, "%s - out of memory\n", __func__);
return -ENOMEM;
}
......@@ -746,11 +747,11 @@ int usb_serial_probe(struct usb_interface *interface,
id = get_iface_id(type, interface);
retval = type->probe(serial, id);
module_put(type->driver.owner);
if (retval) {
dbg("sub driver rejected device");
kfree(serial);
module_put(type->driver.owner);
return retval;
}
}
......@@ -822,6 +823,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (num_bulk_in == 0 || num_bulk_out == 0) {
dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
kfree(serial);
module_put(type->driver.owner);
return -ENODEV;
}
}
......@@ -835,22 +837,15 @@ int usb_serial_probe(struct usb_interface *interface,
dev_err(&interface->dev,
"Generic device with no bulk out, not allowed.\n");
kfree(serial);
module_put(type->driver.owner);
return -EIO;
}
}
#endif
if (!num_ports) {
/* if this device type has a calc_num_ports function, call it */
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;
}
if (type->calc_num_ports)
num_ports = type->calc_num_ports(serial);
module_put(type->driver.owner);
}
if (!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 (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);
module_put(type->driver.owner);
if (retval < 0)
goto probe_error;
serial->attached = 1;
......@@ -1088,10 +1077,12 @@ int usb_serial_probe(struct usb_interface *interface,
exit:
/* success */
usb_set_intfdata(interface, serial);
module_put(type->driver.owner);
return 0;
probe_error:
usb_serial_put(serial);
module_put(type->driver.owner);
return -EIO;
}
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.
* @unbind: Reverses @bind(); called as a side effect of unregistering
* this driver.
* @disconnect: optional driver disconnect method
* @suspend: Notifies when the host stops sending USB traffic,
* after function notifications
* @resume: Notifies configuration when the host restarts USB traffic,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment