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: (32 commits) USB: serial: no unnecessary GFP_ATOMIC in oti6858 USB: serial: fix race between unthrottle and completion handler in visor USB: serial: fix assumption that throttle/unthrottle cannot sleep USB: serial: fix race between unthrottle and completion handler in symbolserial USB: serial: fix race between unthrottle and completion handler in opticon USB: ehci: Fix isoc scheduling boundary checking. USB: storage: When a device returns no sense data, call it a Hardware Error USB: small fix in error case of suspend in generic usbserial code USB: visor: fix trivial accounting bug in visor driver USB: Fix throttling in generic usbserial driver USB: cp210x: Add support for the DW700 UART USB: ipaq: fix oops when device is plugged in USB: isp1362: fix build warnings on 64-bit systems USB: gadget: imx_udc: Use resource size USB: storage: iRiver P7 UNUSUAL_DEV patch USB: musb: make HAVE_CLK support optional USB: xhci: Fix dropping endpoints from the xHC schedule. USB: xhci: Don't wait for a disable slot cmd when HC dies. USB: xhci: Handle canceled URBs when HC dies. USB: xhci: Stop debugging polling loop when HC dies. ...
This commit is contained in:
Коммит
c6c5992723
|
@ -39,7 +39,7 @@
|
|||
#define USBTMC_SIZE_IOBUFFER 2048
|
||||
|
||||
/* Default USB timeout (in milliseconds) */
|
||||
#define USBTMC_TIMEOUT 10
|
||||
#define USBTMC_TIMEOUT 5000
|
||||
|
||||
/*
|
||||
* Maximum number of read cycles to empty bulk in endpoint during CLEAR and
|
||||
|
|
|
@ -1402,7 +1402,8 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
struct clk *clk;
|
||||
void __iomem *base;
|
||||
int ret = 0;
|
||||
int i, res_size;
|
||||
int i;
|
||||
resource_size_t res_size;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
|
@ -1416,7 +1417,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
res_size = res->end - res->start + 1;
|
||||
res_size = resource_size(res);
|
||||
if (!request_mem_region(res->start, res_size, res->name)) {
|
||||
dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
|
||||
res_size, res->start);
|
||||
|
@ -1527,8 +1528,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
|
|||
clk_disable(imx_usb->clk);
|
||||
iounmap(imx_usb->base);
|
||||
|
||||
release_mem_region(imx_usb->res->start,
|
||||
imx_usb->res->end - imx_usb->res->start + 1);
|
||||
release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
|
||||
|
||||
if (pdata->exit)
|
||||
pdata->exit(&pdev->dev);
|
||||
|
|
|
@ -1425,6 +1425,7 @@ iso_stream_schedule (
|
|||
status = -EFBIG;
|
||||
goto fail;
|
||||
}
|
||||
stream->next_uframe = start;
|
||||
goto ready;
|
||||
}
|
||||
|
||||
|
|
|
@ -2284,10 +2284,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd)
|
|||
dev_info(hcd->self.controller, "ISP1362 Memory usage:\n");
|
||||
dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n",
|
||||
istl_size / 2, istl_size, 0, istl_size / 2);
|
||||
dev_info(hcd->self.controller, " INTL: %4d * (%3u+8): %4d @ $%04x\n",
|
||||
dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n",
|
||||
ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE,
|
||||
intl_size, istl_size);
|
||||
dev_info(hcd->self.controller, " ATL : %4d * (%3u+8): %4d @ $%04x\n",
|
||||
dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n",
|
||||
atl_buffers, atl_blksize - PTD_HEADER_SIZE,
|
||||
atl_size, istl_size + intl_size);
|
||||
dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total,
|
||||
|
@ -2677,12 +2677,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
|
|||
DBG(0, "%s: Removing HCD\n", __func__);
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__,
|
||||
(u32)isp1362_hcd->data_reg);
|
||||
DBG(0, "%s: Unmapping data_reg @ %p\n", __func__,
|
||||
isp1362_hcd->data_reg);
|
||||
iounmap(isp1362_hcd->data_reg);
|
||||
|
||||
DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__,
|
||||
(u32)isp1362_hcd->addr_reg);
|
||||
DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__,
|
||||
isp1362_hcd->addr_reg);
|
||||
iounmap(isp1362_hcd->addr_reg);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
|
@ -2810,16 +2810,16 @@ static int __init isp1362_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err6:
|
||||
DBG(0, "%s: Freeing dev %08x\n", __func__, (u32)isp1362_hcd);
|
||||
DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd);
|
||||
usb_put_hcd(hcd);
|
||||
err5:
|
||||
DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, (u32)data_reg);
|
||||
DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg);
|
||||
iounmap(data_reg);
|
||||
err4:
|
||||
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start);
|
||||
release_mem_region(data->start, resource_len(data));
|
||||
err3:
|
||||
DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, (u32)addr_reg);
|
||||
DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg);
|
||||
iounmap(addr_reg);
|
||||
err2:
|
||||
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start);
|
||||
|
|
|
@ -580,7 +580,7 @@ static inline const char *ISP1362_INT_NAME(int n)
|
|||
|
||||
static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr)
|
||||
{
|
||||
unsigned p = (unsigned)ptr;
|
||||
unsigned long p = (unsigned long)ptr;
|
||||
if (!(p & 0xf))
|
||||
isp1362_hcd->stat16++;
|
||||
else if (!(p & 0x7))
|
||||
|
@ -770,7 +770,7 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
|
|||
if (!len)
|
||||
return;
|
||||
|
||||
if ((unsigned)dp & 0x1) {
|
||||
if ((unsigned long)dp & 0x1) {
|
||||
/* not aligned */
|
||||
for (; len > 1; len -= 2) {
|
||||
data = *dp++;
|
||||
|
@ -962,8 +962,8 @@ static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
|
|||
|
||||
isp1362_write_diraddr(isp1362_hcd, offset, len);
|
||||
|
||||
DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %08x\n", __func__,
|
||||
len, offset, (u32)buf);
|
||||
DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
|
||||
__func__, len, offset, buf);
|
||||
|
||||
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
|
||||
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
|
||||
|
@ -982,8 +982,8 @@ static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
|
|||
|
||||
isp1362_write_diraddr(isp1362_hcd, offset, len);
|
||||
|
||||
DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %08x\n", __func__,
|
||||
len, offset, (u32)buf);
|
||||
DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
|
||||
__func__, len, offset, buf);
|
||||
|
||||
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
|
||||
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
|
||||
|
|
|
@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg)
|
|||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
|
||||
if (temp == 0xffffffff) {
|
||||
xhci_dbg(xhci, "HW died, polling stopped.\n");
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
||||
xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
|
||||
xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled);
|
||||
|
@ -776,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
u32 temp;
|
||||
struct xhci_hcd *xhci;
|
||||
struct xhci_td *td;
|
||||
unsigned int ep_index;
|
||||
|
@ -788,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
|
||||
if (ret || !urb->hcpriv)
|
||||
goto done;
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
if (temp == 0xffffffff) {
|
||||
xhci_dbg(xhci, "HW died, freeing TD.\n");
|
||||
td = (struct xhci_td *) urb->hcpriv;
|
||||
|
||||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
|
||||
kfree(td);
|
||||
return ret;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Cancel URB %p\n", urb);
|
||||
xhci_dbg(xhci, "Event ring:\n");
|
||||
|
@ -877,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
ctrl_ctx->drop_flags |= drop_flag;
|
||||
new_drop_flags = ctrl_ctx->drop_flags;
|
||||
|
||||
ctrl_ctx->add_flags = ~drop_flag;
|
||||
ctrl_ctx->add_flags &= ~drop_flag;
|
||||
new_add_flags = ctrl_ctx->add_flags;
|
||||
|
||||
last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
|
||||
|
@ -1410,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
unsigned long flags;
|
||||
u32 state;
|
||||
|
||||
if (udev->slot_id == 0)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* Don't disable the slot if the host controller is dead. */
|
||||
state = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
if (state == 0xffffffff) {
|
||||
xhci_free_virt_device(xhci, udev->slot_id);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
|
||||
|
|
|
@ -313,7 +313,8 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
|
|||
|
||||
if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
|
||||
dev_warn(&interface->dev, "USBLCD model not supported.\n");
|
||||
return -ENODEV;
|
||||
retval = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* set up the endpoint information */
|
||||
|
|
|
@ -8,7 +8,7 @@ comment "Enable Host or Gadget support to see Inventra options"
|
|||
|
||||
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
|
||||
config USB_MUSB_HDRC
|
||||
depends on (USB || USB_GADGET) && HAVE_CLK
|
||||
depends on (USB || USB_GADGET)
|
||||
depends on !SUPERH
|
||||
select NOP_USB_XCEIV if ARCH_DAVINCI
|
||||
select TWL4030_USB if MACH_OMAP_3430SDP
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
|
|
|
@ -95,6 +95,13 @@ struct musb_ep;
|
|||
#endif
|
||||
#endif /* need MUSB gadget selection */
|
||||
|
||||
#ifndef CONFIG_HAVE_CLK
|
||||
/* Dummy stub for clk framework */
|
||||
#define clk_get(dev, id) NULL
|
||||
#define clk_put(clock) do {} while (0)
|
||||
#define clk_enable(clock) do {} while (0)
|
||||
#define clk_disable(clock) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/fs.h>
|
||||
|
|
|
@ -439,15 +439,6 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
|
|||
/* Not implemented - HW has seperate Tx/Rx FIFO */
|
||||
#define MUSB_TXCSR_MODE 0x0000
|
||||
|
||||
/*
|
||||
* Dummy stub for clk framework, it will be removed
|
||||
* until Blackfin supports clk framework
|
||||
*/
|
||||
#define clk_get(dev, id) NULL
|
||||
#define clk_put(clock) do {} while (0)
|
||||
#define clk_enable(clock) do {} while (0)
|
||||
#define clk_disable(clock) do {} while (0)
|
||||
|
||||
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -554,13 +554,12 @@ static void aircable_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct aircable_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
spin_lock_irq(&priv->rx_lock);
|
||||
priv->rx_flags |= THROTTLED;
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
spin_unlock_irq(&priv->rx_lock);
|
||||
}
|
||||
|
||||
/* Based on ftdi_sio.c unthrottle */
|
||||
|
@ -569,14 +568,13 @@ static void aircable_unthrottle(struct tty_struct *tty)
|
|||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct aircable_private *priv = usb_get_serial_port_data(port);
|
||||
int actually_throttled;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
spin_lock_irq(&priv->rx_lock);
|
||||
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
|
||||
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
spin_unlock_irq(&priv->rx_lock);
|
||||
|
||||
if (actually_throttled)
|
||||
schedule_work(&priv->rx_work);
|
||||
|
|
|
@ -113,6 +113,7 @@ static struct usb_device_id id_table [] = {
|
|||
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
|
||||
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
|
||||
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
|
||||
{ USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
|
||||
{ } /* Terminating Entry */
|
||||
};
|
||||
|
||||
|
|
|
@ -1155,13 +1155,12 @@ static void cypress_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct cypress_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->rx_flags = THROTTLED;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1170,14 +1169,13 @@ static void cypress_unthrottle(struct tty_struct *tty)
|
|||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct cypress_private *priv = usb_get_serial_port_data(port);
|
||||
int actually_throttled, result;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
|
||||
priv->rx_flags = 0;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
if (!priv->comm_is_ok)
|
||||
return;
|
||||
|
@ -1185,7 +1183,7 @@ static void cypress_unthrottle(struct tty_struct *tty)
|
|||
if (actually_throttled) {
|
||||
port->interrupt_in_urb->dev = port->serial->dev;
|
||||
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "%s - failed submitting read urb, "
|
||||
"error %d\n", __func__, result);
|
||||
|
|
|
@ -898,16 +898,16 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
|
|||
|
||||
spin_lock_irqsave(&priv->dp_port_lock, flags);
|
||||
|
||||
/* turn throttle off */
|
||||
priv->dp_throttled = 0;
|
||||
priv->dp_throttle_restart = 0;
|
||||
|
||||
/* restart read chain */
|
||||
if (priv->dp_throttle_restart) {
|
||||
port->read_urb->dev = port->serial->dev;
|
||||
ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
/* turn throttle off */
|
||||
priv->dp_throttled = 0;
|
||||
priv->dp_throttle_restart = 0;
|
||||
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
|
||||
if (ret)
|
||||
|
|
|
@ -391,7 +391,7 @@ static void empeg_unthrottle(struct tty_struct *tty)
|
|||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
port->read_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
|
|
|
@ -76,13 +76,7 @@ struct ftdi_private {
|
|||
unsigned long last_dtr_rts; /* saved modem control outputs */
|
||||
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
|
||||
char prev_status, diff_status; /* Used for TIOCMIWAIT */
|
||||
__u8 rx_flags; /* receive state flags (throttling) */
|
||||
spinlock_t rx_lock; /* spinlock for receive state */
|
||||
struct delayed_work rx_work;
|
||||
struct usb_serial_port *port;
|
||||
int rx_processed;
|
||||
unsigned long rx_bytes;
|
||||
|
||||
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
|
||||
(0 for FT232/245) */
|
||||
|
||||
|
@ -737,10 +731,6 @@ static const char *ftdi_chip_name[] = {
|
|||
/* Constants for read urb and write urb */
|
||||
#define BUFSZ 512
|
||||
|
||||
/* rx_flags */
|
||||
#define THROTTLED 0x01
|
||||
#define ACTUALLY_THROTTLED 0x02
|
||||
|
||||
/* Used for TIOCMIWAIT */
|
||||
#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
|
||||
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
|
||||
|
@ -763,7 +753,7 @@ static int ftdi_write_room(struct tty_struct *tty);
|
|||
static int ftdi_chars_in_buffer(struct tty_struct *tty);
|
||||
static void ftdi_write_bulk_callback(struct urb *urb);
|
||||
static void ftdi_read_bulk_callback(struct urb *urb);
|
||||
static void ftdi_process_read(struct work_struct *work);
|
||||
static void ftdi_process_read(struct usb_serial_port *port);
|
||||
static void ftdi_set_termios(struct tty_struct *tty,
|
||||
struct usb_serial_port *port, struct ktermios *old);
|
||||
static int ftdi_tiocmget(struct tty_struct *tty, struct file *file);
|
||||
|
@ -1234,7 +1224,6 @@ static int set_serial_info(struct tty_struct *tty,
|
|||
(new_serial.flags & ASYNC_FLAGS));
|
||||
priv->custom_divisor = new_serial.custom_divisor;
|
||||
|
||||
tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
write_latency_timer(port);
|
||||
|
||||
check_and_exit:
|
||||
|
@ -1527,7 +1516,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
|||
}
|
||||
|
||||
kref_init(&priv->kref);
|
||||
spin_lock_init(&priv->rx_lock);
|
||||
spin_lock_init(&priv->tx_lock);
|
||||
init_waitqueue_head(&priv->delta_msr_wait);
|
||||
/* This will push the characters through immediately rather
|
||||
|
@ -1549,7 +1537,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
|
|||
port->read_urb->transfer_buffer_length = BUFSZ;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read);
|
||||
priv->port = port;
|
||||
|
||||
/* Free port's existing write urb and transfer buffer. */
|
||||
|
@ -1686,6 +1673,26 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
|
||||
{
|
||||
struct urb *urb = port->read_urb;
|
||||
struct usb_serial *serial = port->serial;
|
||||
int result;
|
||||
|
||||
usb_fill_bulk_urb(urb, serial->dev,
|
||||
usb_rcvbulkpipe(serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
urb->transfer_buffer,
|
||||
urb->transfer_buffer_length,
|
||||
ftdi_read_bulk_callback, port);
|
||||
result = usb_submit_urb(urb, mem_flags);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
|
||||
{ /* ftdi_open */
|
||||
struct usb_device *dev = port->serial->dev;
|
||||
|
@ -1700,12 +1707,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
spin_lock_irqsave(&priv->tx_lock, flags);
|
||||
priv->tx_bytes = 0;
|
||||
spin_unlock_irqrestore(&priv->tx_lock, flags);
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
priv->rx_bytes = 0;
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
|
||||
if (tty)
|
||||
tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
write_latency_timer(port);
|
||||
|
||||
|
@ -1725,23 +1726,14 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
|
|||
ftdi_set_termios(tty, port, tty->termios);
|
||||
|
||||
/* Not throttled */
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->throttled = 0;
|
||||
port->throttle_req = 0;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
/* Start reading from the device */
|
||||
priv->rx_processed = 0;
|
||||
usb_fill_bulk_urb(port->read_urb, dev,
|
||||
usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
|
||||
port->read_urb->transfer_buffer,
|
||||
port->read_urb->transfer_buffer_length,
|
||||
ftdi_read_bulk_callback, port);
|
||||
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
else
|
||||
result = ftdi_submit_read_urb(port, GFP_KERNEL);
|
||||
if (!result)
|
||||
kref_get(&priv->kref);
|
||||
|
||||
return result;
|
||||
|
@ -1787,10 +1779,6 @@ static void ftdi_close(struct usb_serial_port *port)
|
|||
|
||||
dbg("%s", __func__);
|
||||
|
||||
|
||||
/* cancel any scheduled reading */
|
||||
cancel_delayed_work_sync(&priv->rx_work);
|
||||
|
||||
/* shutdown our bulk read */
|
||||
usb_kill_urb(port->read_urb);
|
||||
kref_put(&priv->kref, ftdi_sio_priv_release);
|
||||
|
@ -2013,271 +2001,121 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty)
|
|||
return buffered;
|
||||
}
|
||||
|
||||
static int ftdi_process_packet(struct tty_struct *tty,
|
||||
struct usb_serial_port *port, struct ftdi_private *priv,
|
||||
char *packet, int len)
|
||||
{
|
||||
int i;
|
||||
char status;
|
||||
char flag;
|
||||
char *ch;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
if (len < 2) {
|
||||
dbg("malformed packet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compare new line status to the old one, signal if different/
|
||||
N.B. packet may be processed more than once, but differences
|
||||
are only processed once. */
|
||||
status = packet[0] & FTDI_STATUS_B0_MASK;
|
||||
if (status != priv->prev_status) {
|
||||
priv->diff_status |= status ^ priv->prev_status;
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
priv->prev_status = status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Although the device uses a bitmask and hence can have multiple
|
||||
* errors on a packet - the order here sets the priority the error is
|
||||
* returned to the tty layer.
|
||||
*/
|
||||
flag = TTY_NORMAL;
|
||||
if (packet[1] & FTDI_RS_OE) {
|
||||
flag = TTY_OVERRUN;
|
||||
dbg("OVERRRUN error");
|
||||
}
|
||||
if (packet[1] & FTDI_RS_BI) {
|
||||
flag = TTY_BREAK;
|
||||
dbg("BREAK received");
|
||||
usb_serial_handle_break(port);
|
||||
}
|
||||
if (packet[1] & FTDI_RS_PE) {
|
||||
flag = TTY_PARITY;
|
||||
dbg("PARITY error");
|
||||
}
|
||||
if (packet[1] & FTDI_RS_FE) {
|
||||
flag = TTY_FRAME;
|
||||
dbg("FRAMING error");
|
||||
}
|
||||
|
||||
len -= 2;
|
||||
if (!len)
|
||||
return 0; /* status only */
|
||||
ch = packet + 2;
|
||||
|
||||
if (!(port->console && port->sysrq) && flag == TTY_NORMAL)
|
||||
tty_insert_flip_string(tty, ch, len);
|
||||
else {
|
||||
for (i = 0; i < len; i++, ch++) {
|
||||
if (!usb_serial_handle_sysrq_char(tty, port, *ch))
|
||||
tty_insert_flip_char(tty, *ch, flag);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ftdi_process_read(struct usb_serial_port *port)
|
||||
{
|
||||
struct urb *urb = port->read_urb;
|
||||
struct tty_struct *tty;
|
||||
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
||||
char *data = (char *)urb->transfer_buffer;
|
||||
int i;
|
||||
int len;
|
||||
int count = 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
|
||||
len = min_t(int, urb->actual_length - i, priv->max_packet_size);
|
||||
count += ftdi_process_packet(tty, port, priv, &data[i], len);
|
||||
}
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static void ftdi_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_serial_port *port = urb->context;
|
||||
struct tty_struct *tty;
|
||||
struct ftdi_private *priv;
|
||||
unsigned long countread;
|
||||
unsigned long flags;
|
||||
int status = urb->status;
|
||||
|
||||
if (urb->number_of_packets > 0) {
|
||||
dev_err(&port->dev, "%s transfer_buffer_length %d "
|
||||
"actual_length %d number of packets %d\n", __func__,
|
||||
urb->transfer_buffer_length,
|
||||
urb->actual_length, urb->number_of_packets);
|
||||
dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
|
||||
urb->transfer_flags);
|
||||
}
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
if (port->port.count <= 0)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty) {
|
||||
dbg("%s - bad tty pointer - exiting", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
priv = usb_get_serial_port_data(port);
|
||||
if (!priv) {
|
||||
dbg("%s - bad port private data pointer - exiting", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (urb != port->read_urb)
|
||||
dev_err(&port->dev, "%s - Not my urb!\n", __func__);
|
||||
|
||||
if (status) {
|
||||
/* This will happen at close every time so it is a dbg not an
|
||||
err */
|
||||
dbg("(this is ok on close) nonzero read bulk status received: %d", status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* count data bytes, but not status bytes */
|
||||
countread = urb->actual_length;
|
||||
countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
priv->rx_bytes += countread;
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
|
||||
ftdi_process_read(&priv->rx_work.work);
|
||||
out:
|
||||
tty_kref_put(tty);
|
||||
} /* ftdi_read_bulk_callback */
|
||||
|
||||
|
||||
static void ftdi_process_read(struct work_struct *work)
|
||||
{ /* ftdi_process_read */
|
||||
struct ftdi_private *priv =
|
||||
container_of(work, struct ftdi_private, rx_work.work);
|
||||
struct usb_serial_port *port = priv->port;
|
||||
struct urb *urb;
|
||||
struct tty_struct *tty;
|
||||
char error_flag;
|
||||
unsigned char *data;
|
||||
|
||||
int i;
|
||||
int result;
|
||||
int need_flip;
|
||||
int packet_offset;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
if (port->port.count <= 0)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&port->port);
|
||||
if (!tty) {
|
||||
dbg("%s - bad tty pointer - exiting", __func__);
|
||||
if (urb->status) {
|
||||
dbg("%s - nonzero read bulk status received: %d",
|
||||
__func__, urb->status);
|
||||
return;
|
||||
}
|
||||
|
||||
priv = usb_get_serial_port_data(port);
|
||||
if (!priv) {
|
||||
dbg("%s - bad port private data pointer - exiting", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
urb = port->read_urb;
|
||||
if (!urb) {
|
||||
dbg("%s - bad read_urb pointer - exiting", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = urb->transfer_buffer;
|
||||
|
||||
if (priv->rx_processed) {
|
||||
dbg("%s - already processed: %d bytes, %d remain", __func__,
|
||||
priv->rx_processed,
|
||||
urb->actual_length - priv->rx_processed);
|
||||
} else {
|
||||
/* The first two bytes of every read packet are status */
|
||||
if (urb->actual_length > 2)
|
||||
usb_serial_debug_data(debug, &port->dev, __func__,
|
||||
urb->actual_length, data);
|
||||
else
|
||||
dbg("Status only: %03oo %03oo", data[0], data[1]);
|
||||
}
|
||||
|
||||
|
||||
/* TO DO -- check for hung up line and handle appropriately: */
|
||||
/* send hangup */
|
||||
/* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */
|
||||
/* if CD is dropped and the line is not CLOCAL then we should hangup */
|
||||
|
||||
need_flip = 0;
|
||||
for (packet_offset = priv->rx_processed;
|
||||
packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
|
||||
int length;
|
||||
|
||||
/* Compare new line status to the old one, signal if different/
|
||||
N.B. packet may be processed more than once, but differences
|
||||
are only processed once. */
|
||||
char new_status = data[packet_offset + 0] &
|
||||
FTDI_STATUS_B0_MASK;
|
||||
if (new_status != priv->prev_status) {
|
||||
priv->diff_status |=
|
||||
new_status ^ priv->prev_status;
|
||||
wake_up_interruptible(&priv->delta_msr_wait);
|
||||
priv->prev_status = new_status;
|
||||
}
|
||||
|
||||
length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
|
||||
if (length < 0) {
|
||||
dev_err(&port->dev, "%s - bad packet length: %d\n",
|
||||
__func__, length+2);
|
||||
length = 0;
|
||||
}
|
||||
|
||||
if (priv->rx_flags & THROTTLED) {
|
||||
dbg("%s - throttled", __func__);
|
||||
break;
|
||||
}
|
||||
if (tty_buffer_request_room(tty, length) < length) {
|
||||
/* break out & wait for throttling/unthrottling to
|
||||
happen */
|
||||
dbg("%s - receive room low", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle errors and break */
|
||||
error_flag = TTY_NORMAL;
|
||||
/* Although the device uses a bitmask and hence can have
|
||||
multiple errors on a packet - the order here sets the
|
||||
priority the error is returned to the tty layer */
|
||||
|
||||
if (data[packet_offset+1] & FTDI_RS_OE) {
|
||||
error_flag = TTY_OVERRUN;
|
||||
dbg("OVERRRUN error");
|
||||
}
|
||||
if (data[packet_offset+1] & FTDI_RS_BI) {
|
||||
error_flag = TTY_BREAK;
|
||||
dbg("BREAK received");
|
||||
usb_serial_handle_break(port);
|
||||
}
|
||||
if (data[packet_offset+1] & FTDI_RS_PE) {
|
||||
error_flag = TTY_PARITY;
|
||||
dbg("PARITY error");
|
||||
}
|
||||
if (data[packet_offset+1] & FTDI_RS_FE) {
|
||||
error_flag = TTY_FRAME;
|
||||
dbg("FRAMING error");
|
||||
}
|
||||
if (length > 0) {
|
||||
for (i = 2; i < length+2; i++) {
|
||||
/* Note that the error flag is duplicated for
|
||||
every character received since we don't know
|
||||
which character it applied to */
|
||||
if (!usb_serial_handle_sysrq_char(tty, port,
|
||||
data[packet_offset + i]))
|
||||
tty_insert_flip_char(tty,
|
||||
data[packet_offset + i],
|
||||
error_flag);
|
||||
}
|
||||
need_flip = 1;
|
||||
}
|
||||
|
||||
#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
|
||||
/* if a parity error is detected you get status packets forever
|
||||
until a character is sent without a parity error.
|
||||
This doesn't work well since the application receives a
|
||||
never ending stream of bad data - even though new data
|
||||
hasn't been sent. Therefore I (bill) have taken this out.
|
||||
However - this might make sense for framing errors and so on
|
||||
so I am leaving the code in for now.
|
||||
*/
|
||||
else {
|
||||
if (error_flag != TTY_NORMAL) {
|
||||
dbg("error_flag is not normal");
|
||||
/* In this case it is just status - if that is
|
||||
an error send a bad character */
|
||||
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(tty, 0xff, error_flag);
|
||||
need_flip = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} /* "for(packet_offset=0..." */
|
||||
|
||||
/* Low latency */
|
||||
if (need_flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
if (packet_offset < urb->actual_length) {
|
||||
/* not completely processed - record progress */
|
||||
priv->rx_processed = packet_offset;
|
||||
dbg("%s - incomplete, %d bytes processed, %d remain",
|
||||
__func__, packet_offset,
|
||||
urb->actual_length - packet_offset);
|
||||
/* check if we were throttled while processing */
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
if (priv->rx_flags & THROTTLED) {
|
||||
priv->rx_flags |= ACTUALLY_THROTTLED;
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
dbg("%s - deferring remainder until unthrottled",
|
||||
__func__);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
/* if the port is closed stop trying to read */
|
||||
if (port->port.count > 0)
|
||||
/* delay processing of remainder */
|
||||
schedule_delayed_work(&priv->rx_work, 1);
|
||||
else
|
||||
dbg("%s - port is closed", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* urb is completely processed */
|
||||
priv->rx_processed = 0;
|
||||
|
||||
/* if the port is closed stop trying to read */
|
||||
if (port->port.count > 0) {
|
||||
/* Continue trying to always read */
|
||||
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
|
||||
usb_rcvbulkpipe(port->serial->dev,
|
||||
port->bulk_in_endpointAddress),
|
||||
port->read_urb->transfer_buffer,
|
||||
port->read_urb->transfer_buffer_length,
|
||||
ftdi_read_bulk_callback, port);
|
||||
|
||||
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed resubmitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
}
|
||||
out:
|
||||
tty_kref_put(tty);
|
||||
} /* ftdi_process_read */
|
||||
usb_serial_debug_data(debug, &port->dev, __func__,
|
||||
urb->actual_length, urb->transfer_buffer);
|
||||
ftdi_process_read(port);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->throttled = port->throttle_req;
|
||||
if (!port->throttled) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
ftdi_submit_read_urb(port, GFP_ATOMIC);
|
||||
} else
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
|
||||
{
|
||||
|
@ -2609,33 +2447,31 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
|
|||
static void ftdi_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
priv->rx_flags |= THROTTLED;
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->throttle_req = 1;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static void ftdi_unthrottle(struct tty_struct *tty)
|
||||
void ftdi_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct ftdi_private *priv = usb_get_serial_port_data(port);
|
||||
int actually_throttled;
|
||||
int was_throttled;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->rx_lock, flags);
|
||||
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
|
||||
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
|
||||
spin_unlock_irqrestore(&priv->rx_lock, flags);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
was_throttled = port->throttled;
|
||||
port->throttled = port->throttle_req = 0;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (actually_throttled)
|
||||
schedule_delayed_work(&priv->rx_work, 0);
|
||||
/* Resubmit urb if throttled and open. */
|
||||
if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
|
||||
ftdi_submit_read_urb(port, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int __init ftdi_init(void)
|
||||
|
|
|
@ -1390,14 +1390,13 @@ static void garmin_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
/* set flag, data received will be put into a queue
|
||||
for later processing */
|
||||
spin_lock_irqsave(&garmin_data_p->lock, flags);
|
||||
spin_lock_irq(&garmin_data_p->lock);
|
||||
garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
|
||||
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
|
||||
spin_unlock_irq(&garmin_data_p->lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1405,13 +1404,12 @@ static void garmin_unthrottle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
int status;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
spin_lock_irqsave(&garmin_data_p->lock, flags);
|
||||
spin_lock_irq(&garmin_data_p->lock);
|
||||
garmin_data_p->flags &= ~FLAGS_THROTTLED;
|
||||
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
|
||||
spin_unlock_irq(&garmin_data_p->lock);
|
||||
|
||||
/* in native mode send queued data to tty, in
|
||||
serial mode nothing needs to be done here */
|
||||
|
@ -1419,7 +1417,7 @@ static void garmin_unthrottle(struct tty_struct *tty)
|
|||
garmin_flush_queue(garmin_data_p);
|
||||
|
||||
if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
|
||||
status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
status = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (status)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed resubmitting read urb, error %d\n",
|
||||
|
|
|
@ -546,7 +546,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
|
|||
|
||||
if (was_throttled) {
|
||||
/* Resume reading from device */
|
||||
usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
|
||||
flush_and_resubmit_read_urb(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -966,6 +966,15 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
|
|||
static int ipaq_startup(struct usb_serial *serial)
|
||||
{
|
||||
dbg("%s", __func__);
|
||||
|
||||
/* Some of the devices in ipaq_id_table[] are composite, and we
|
||||
* shouldn't bind to all the interfaces. This test will rule out
|
||||
* some obviously invalid possibilities.
|
||||
*/
|
||||
if (serial->num_bulk_in < serial->num_ports ||
|
||||
serial->num_bulk_out < serial->num_ports)
|
||||
return -ENODEV;
|
||||
|
||||
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
|
||||
/*
|
||||
* FIXME: HP iPaq rx3715, possibly others, have 1 config that
|
||||
|
|
|
@ -290,7 +290,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
|
|||
/* just restart the receive interrupt URB */
|
||||
dbg("keyspan_pda_rx_unthrottle port %d", port->number);
|
||||
port->interrupt_in_urb->dev = port->serial->dev;
|
||||
if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC))
|
||||
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
|
||||
dbg(" usb_submit_urb(read urb) failed");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -951,7 +951,7 @@ static void klsi_105_unthrottle(struct tty_struct *tty)
|
|||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
port->read_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
|
|
|
@ -777,20 +777,19 @@ static void mct_u232_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct mct_u232_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
unsigned int control_state;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->rx_flags |= THROTTLED;
|
||||
if (C_CRTSCTS(tty)) {
|
||||
priv->control_state &= ~TIOCM_RTS;
|
||||
control_state = priv->control_state;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
(void) mct_u232_set_modem_ctrl(port->serial, control_state);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -799,20 +798,19 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct mct_u232_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
unsigned int control_state;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
|
||||
priv->rx_flags &= ~THROTTLED;
|
||||
priv->control_state |= TIOCM_RTS;
|
||||
control_state = priv->control_state;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
(void) mct_u232_set_modem_ctrl(port->serial, control_state);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -314,21 +314,24 @@ static void opticon_unthrottle(struct tty_struct *tty)
|
|||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct opticon_private *priv = usb_get_serial_data(port->serial);
|
||||
unsigned long flags;
|
||||
int result;
|
||||
int result, was_throttled;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
priv->throttled = false;
|
||||
was_throttled = priv->actually_throttled;
|
||||
priv->actually_throttled = false;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
priv->bulk_read_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
if (was_throttled) {
|
||||
result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
}
|
||||
}
|
||||
|
||||
static int opticon_tiocmget(struct tty_struct *tty, struct file *file)
|
||||
|
|
|
@ -165,6 +165,7 @@ static int option_resume(struct usb_serial *serial);
|
|||
#define HUAWEI_PRODUCT_E143D 0x143D
|
||||
#define HUAWEI_PRODUCT_E143E 0x143E
|
||||
#define HUAWEI_PRODUCT_E143F 0x143F
|
||||
#define HUAWEI_PRODUCT_E14AC 0x14AC
|
||||
|
||||
#define QUANTA_VENDOR_ID 0x0408
|
||||
#define QUANTA_PRODUCT_Q101 0xEA02
|
||||
|
@ -318,6 +319,7 @@ static int option_resume(struct usb_serial *serial);
|
|||
/* TOSHIBA PRODUCTS */
|
||||
#define TOSHIBA_VENDOR_ID 0x0930
|
||||
#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302
|
||||
#define TOSHIBA_PRODUCT_G450 0x0d45
|
||||
|
||||
#define ALINK_VENDOR_ID 0x1e0e
|
||||
#define ALINK_PRODUCT_3GU 0x9200
|
||||
|
@ -424,6 +426,7 @@ static struct usb_device_id option_ids[] = {
|
|||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
|
||||
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
|
||||
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) },
|
||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */
|
||||
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */
|
||||
|
@ -581,6 +584,7 @@ static struct usb_device_id option_ids[] = {
|
|||
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
|
||||
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
|
||||
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
|
||||
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
|
||||
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
|
||||
{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
|
||||
|
|
|
@ -288,7 +288,7 @@ static void setup_line(struct work_struct *work)
|
|||
|
||||
dbg("%s(): submitting interrupt urb", __func__);
|
||||
port->interrupt_in_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
|
||||
if (result != 0) {
|
||||
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
|
||||
" with error %d\n", __func__, result);
|
||||
|
@ -335,7 +335,7 @@ void send_data(struct work_struct *work)
|
|||
|
||||
dbg("%s(): submitting interrupt urb", __func__);
|
||||
port->interrupt_in_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
|
||||
if (result != 0) {
|
||||
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
|
||||
" with error %d\n", __func__, result);
|
||||
|
@ -349,7 +349,7 @@ void send_data(struct work_struct *work)
|
|||
|
||||
port->write_urb->transfer_buffer_length = count;
|
||||
port->write_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
result = usb_submit_urb(port->write_urb, GFP_NOIO);
|
||||
if (result != 0) {
|
||||
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
|
||||
" with error %d\n", __func__, result);
|
||||
|
|
|
@ -1046,13 +1046,15 @@ static void pl2303_push_data(struct tty_struct *tty,
|
|||
/* overrun is special, not associated with a char */
|
||||
if (line_status & UART_OVERRUN_ERROR)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
if (port->console && port->sysrq) {
|
||||
|
||||
if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
|
||||
tty_insert_flip_string(tty, data, urb->actual_length);
|
||||
else {
|
||||
int i;
|
||||
for (i = 0; i < urb->actual_length; ++i)
|
||||
if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
|
||||
tty_insert_flip_char(tty, data[i], tty_flag);
|
||||
} else
|
||||
tty_insert_flip_string(tty, data, urb->actual_length);
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
|
||||
*/
|
||||
|
||||
#define DRIVER_VERSION "v.1.3.7"
|
||||
#define DRIVER_VERSION "v.1.3.8"
|
||||
#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
|
||||
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
|
||||
|
||||
|
|
|
@ -165,34 +165,36 @@ static void symbol_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct symbol_private *priv = usb_get_serial_data(port->serial);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->throttled = true;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
static void symbol_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct symbol_private *priv = usb_get_serial_data(port->serial);
|
||||
unsigned long flags;
|
||||
int result;
|
||||
bool was_throttled;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->throttled = false;
|
||||
was_throttled = priv->actually_throttled;
|
||||
priv->actually_throttled = false;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
priv->int_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(priv->int_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
if (was_throttled) {
|
||||
result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
}
|
||||
}
|
||||
|
||||
static int symbol_startup(struct usb_serial *serial)
|
||||
|
|
|
@ -156,7 +156,8 @@ static void destroy_serial(struct kref *kref)
|
|||
if (serial->minor != SERIAL_TTY_NO_MINOR)
|
||||
return_serial(serial);
|
||||
|
||||
serial->type->release(serial);
|
||||
if (serial->attached)
|
||||
serial->type->release(serial);
|
||||
|
||||
/* Now that nothing is using the ports, they can be freed */
|
||||
for (i = 0; i < serial->num_port_pointers; ++i) {
|
||||
|
@ -1059,12 +1060,15 @@ int usb_serial_probe(struct usb_interface *interface,
|
|||
module_put(type->driver.owner);
|
||||
if (retval < 0)
|
||||
goto probe_error;
|
||||
serial->attached = 1;
|
||||
if (retval > 0) {
|
||||
/* quietly accept this device, but don't bind to a
|
||||
serial port as it's about to disappear */
|
||||
serial->num_ports = 0;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
serial->attached = 1;
|
||||
}
|
||||
|
||||
if (get_free_serial(serial, num_ports, &minor) == NULL) {
|
||||
|
@ -1164,8 +1168,10 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
|
|||
|
||||
if (serial->type->suspend) {
|
||||
r = serial->type->suspend(serial, message);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
serial->suspending = 0;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < serial->num_ports; ++i) {
|
||||
|
|
|
@ -513,7 +513,8 @@ static void visor_read_bulk_callback(struct urb *urb)
|
|||
tty_kref_put(tty);
|
||||
}
|
||||
spin_lock(&priv->lock);
|
||||
priv->bytes_in += available_room;
|
||||
if (tty)
|
||||
priv->bytes_in += available_room;
|
||||
|
||||
} else {
|
||||
spin_lock(&priv->lock);
|
||||
|
@ -582,12 +583,11 @@ static void visor_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct visor_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->throttled = 1;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,21 +595,23 @@ static void visor_unthrottle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct visor_private *priv = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
int result;
|
||||
int result, was_throttled;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->throttled = 0;
|
||||
was_throttled = priv->actually_throttled;
|
||||
priv->actually_throttled = 0;
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
port->read_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
if (was_throttled) {
|
||||
port->read_urb->dev = port->serial->dev;
|
||||
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
|
||||
if (result)
|
||||
dev_err(&port->dev,
|
||||
"%s - failed submitting read urb, error %d\n",
|
||||
__func__, result);
|
||||
}
|
||||
}
|
||||
|
||||
static int palm_os_3_probe(struct usb_serial *serial,
|
||||
|
|
|
@ -949,13 +949,12 @@ static void whiteheat_throttle(struct tty_struct *tty)
|
|||
{
|
||||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
spin_lock_irq(&info->lock);
|
||||
info->flags |= THROTTLED;
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
spin_unlock_irq(&info->lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -966,14 +965,13 @@ static void whiteheat_unthrottle(struct tty_struct *tty)
|
|||
struct usb_serial_port *port = tty->driver_data;
|
||||
struct whiteheat_private *info = usb_get_serial_port_data(port);
|
||||
int actually_throttled;
|
||||
unsigned long flags;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
||||
spin_lock_irqsave(&info->lock, flags);
|
||||
spin_lock_irq(&info->lock);
|
||||
actually_throttled = info->flags & ACTUALLY_THROTTLED;
|
||||
info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
|
||||
spin_unlock_irqrestore(&info->lock, flags);
|
||||
spin_unlock_irq(&info->lock);
|
||||
|
||||
if (actually_throttled)
|
||||
rx_data_softint(&info->rx_work);
|
||||
|
|
|
@ -768,17 +768,32 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
|
|||
/* set the result so the higher layers expect this data */
|
||||
srb->result = SAM_STAT_CHECK_CONDITION;
|
||||
|
||||
/* If things are really okay, then let's show that. Zero
|
||||
* out the sense buffer so the higher layers won't realize
|
||||
* we did an unsolicited auto-sense. */
|
||||
if (result == USB_STOR_TRANSPORT_GOOD &&
|
||||
/* Filemark 0, ignore EOM, ILI 0, no sense */
|
||||
/* We often get empty sense data. This could indicate that
|
||||
* everything worked or that there was an unspecified
|
||||
* problem. We have to decide which.
|
||||
*/
|
||||
if ( /* Filemark 0, ignore EOM, ILI 0, no sense */
|
||||
(srb->sense_buffer[2] & 0xaf) == 0 &&
|
||||
/* No ASC or ASCQ */
|
||||
srb->sense_buffer[12] == 0 &&
|
||||
srb->sense_buffer[13] == 0) {
|
||||
srb->result = SAM_STAT_GOOD;
|
||||
srb->sense_buffer[0] = 0x0;
|
||||
|
||||
/* If things are really okay, then let's show that.
|
||||
* Zero out the sense buffer so the higher layers
|
||||
* won't realize we did an unsolicited auto-sense.
|
||||
*/
|
||||
if (result == USB_STOR_TRANSPORT_GOOD) {
|
||||
srb->result = SAM_STAT_GOOD;
|
||||
srb->sense_buffer[0] = 0x0;
|
||||
|
||||
/* If there was a problem, report an unspecified
|
||||
* hardware error to prevent the higher layers from
|
||||
* entering an infinite retry loop.
|
||||
*/
|
||||
} else {
|
||||
srb->result = DID_ERROR << 16;
|
||||
srb->sense_buffer[2] = HARDWARE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1823,6 +1823,13 @@ UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
|
|||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_IGNORE_RESIDUE ),
|
||||
|
||||
/* Reported by Sergey Pinaev <dfo@antex.ru> */
|
||||
UNUSUAL_DEV( 0x4102, 0x1059, 0x0000, 0x0000,
|
||||
"iRiver",
|
||||
"P7K",
|
||||
US_SC_DEVICE, US_PR_DEVICE, NULL,
|
||||
US_FL_MAX_SECTORS_64 ),
|
||||
|
||||
/*
|
||||
* David Härdeman <david@2gen.com>
|
||||
* The key makes the SCSI stack print confusing (but harmless) messages
|
||||
|
|
|
@ -150,6 +150,7 @@ struct usb_serial {
|
|||
struct usb_interface *interface;
|
||||
unsigned char disconnected:1;
|
||||
unsigned char suspending:1;
|
||||
unsigned char attached:1;
|
||||
unsigned char minor;
|
||||
unsigned char num_ports;
|
||||
unsigned char num_port_pointers;
|
||||
|
|
Загрузка…
Ссылка в новой задаче