diff options
12 files changed, 2453 insertions, 1045 deletions
diff --git a/driver-core/driver-core-add-bus_notify_bind_driver.patch b/driver-core/driver-core-add-bus_notify_bind_driver.patch new file mode 100644 index 00000000000000..ba46fc3d39125d --- /dev/null +++ b/driver-core/driver-core-add-bus_notify_bind_driver.patch @@ -0,0 +1,71 @@ +From magnus.damm@gmail.com Mon Jul 26 14:18:23 2010 +From: Magnus Damm <magnus.damm@gmail.com> +To: linux-kernel@vger.kernel.org +Cc: Magnus Damm <magnus.damm@gmail.com>, gregkh@suse.de +Date: Fri, 23 Jul 2010 19:56:18 +0900 +Message-Id: <20100723105618.11690.75431.sendpatchset@t400s> +Subject: Driver core: Add BUS_NOTIFY_BIND_DRIVER + +From: Magnus Damm <damm@opensource.se> + +Add BUS_NOTIFY_BIND_DRIVER as a bus notifier event. + +For driver binding/unbinding we with this in +place have the following bus notifier events: + - BUS_NOTIFY_BIND_DRIVER - before ->probe() + - BUS_NOTIFY_BOUND_DRIVER - after ->probe() + - BUS_NOTIFY_UNBIND_DRIVER - before ->remove() + - BUS_NOTIFY_UNBOUND_DRIVER - after ->remove() + +The event BUS_NOTIFY_BIND_DRIVER allows bus code +to be notified that ->probe() is about to be called. + +Useful for bus code that needs to setup hardware before +the driver gets to run. With this in place platform +drivers can be loaded and unloaded as modules and the +new BIND event allows bus code to control for instance +device clocks that must be enabled before the driver +can be executed. + +Without this patch there is no way for the bus code to +get notified that a modular driver is about to be probed. + +Signed-off-by: Magnus Damm <damm@opensource.se> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/dd.c | 4 ++++ + include/linux/device.h | 8 +++++--- + 2 files changed, 9 insertions(+), 3 deletions(-) + +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -51,6 +51,10 @@ static int driver_sysfs_add(struct devic + { + int ret; + ++ if (dev->bus) ++ blocking_notifier_call_chain(&dev->bus->p->bus_notifier, ++ BUS_NOTIFY_BIND_DRIVER, dev); ++ + ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, + kobject_name(&dev->kobj)); + if (ret == 0) { +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -109,10 +109,12 @@ extern int bus_unregister_notifier(struc + */ + #define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ + #define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device removed */ +-#define BUS_NOTIFY_BOUND_DRIVER 0x00000003 /* driver bound to device */ +-#define BUS_NOTIFY_UNBIND_DRIVER 0x00000004 /* driver about to be ++#define BUS_NOTIFY_BIND_DRIVER 0x00000003 /* driver about to be ++ bound */ ++#define BUS_NOTIFY_BOUND_DRIVER 0x00000004 /* driver bound to device */ ++#define BUS_NOTIFY_UNBIND_DRIVER 0x00000005 /* driver about to be + unbound */ +-#define BUS_NOTIFY_UNBOUND_DRIVER 0x00000005 /* driver is unbound ++#define BUS_NOTIFY_UNBOUND_DRIVER 0x00000006 /* driver is unbound + from the device */ + + extern struct kset *bus_get_kset(struct bus_type *bus); @@ -47,6 +47,7 @@ driver-core/sysfs-fix-discrepancies-between-implementation-and-documentation.pat driver-core/sysfs-fix-one-more-signature-discrepancy-between-sysfs-implementation-and-docs.patch driver-core/debugfs-no-longer-needs-to-depend-on-sysfs.patch driver-core/driver-core-fix-memory-leak-one-one-error-path-in-bus_register.patch +driver-core/driver-core-add-bus_notify_bind_driver.patch # can we really drop it? (nope, not yet...) #driver-core/driver-core-remove-config_sysfs_deprecated.patch @@ -115,6 +116,12 @@ tty/serial-mcf-don-t-take-spinlocks-in-already-protected-functions.patch tty/serial-mmio32-support-for-8250_early.c.patch tty/timbuart-use-__devinit-and-__devexit-macros-for-probe-and-remove.patch tty/serial-68328serial.c-remove-dead-alma_ans-dragonixvz-m68ez328ads.patch +tty/serial-add-support-for-ox16pci958-card.patch +tty/hsu-driver-for-medfield-high-speed-uart-device.patch +tty/hsu-add-a-periodic-timer-to-check-dma-rx-channel.patch +tty/hsu-some-code-cleanup.patch +tty/hsu-call-pci-pm-hooks-in-suspend-resume-function.patch +tty/mxser-remove-unnesesary-null-check.patch ################################### @@ -139,7 +146,6 @@ usb/usb-otg.h-fix-the-mixup-in-parameters-order.patch usb/usb-host-eliminate-null-dereference.patch usb/usb-isd200.c-remove-unnecessary-kmalloc-cast.patch usb/usb-throw-away-custom-hex-digit-methods.patch -usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch usb/usb-ehci-ehci-1.1-addendum-preparation.patch usb/usb-ehci-ehci-1.1-addendum-basic-lpm-feature-support.patch usb/usb-ehci-ehci-1.1-addendum-enable-per-port-change-detect-bits.patch @@ -246,6 +252,9 @@ usb/usb-s3c-hsotg-add-support-for-clock-gating.patch usb/usb-powerpc-fsl_soc.c-remove-fsl-usb-platform-code.patch usb/usb-add-of_platform-glue-driver-for-fsl-usb-dr-controller.patch usb/usb-add-usb-ehci-support-for-mpc5121-soc.patch +usb/usb-serial-enabling-support-for-segway-rmp-in-ftdi_sio.patch +usb/usb-imx21-hcd-set-task-state-with-schedule_timeout_uninterruptible.patch +usb/usb-gadget-file_storage-serial-parameter-even-if-not-test-mode.patch # staging stuff is now in the staging-next tree on git.kernel.org diff --git a/tty/hsu-add-a-periodic-timer-to-check-dma-rx-channel.patch b/tty/hsu-add-a-periodic-timer-to-check-dma-rx-channel.patch new file mode 100644 index 00000000000000..6553a6dc05b74c --- /dev/null +++ b/tty/hsu-add-a-periodic-timer-to-check-dma-rx-channel.patch @@ -0,0 +1,142 @@ +From alan@linux.intel.com Mon Jul 26 14:23:17 2010 +From: Alan Cox <alan@linux.intel.com> +Subject: hsu: add a periodic timer to check dma rx channel +To: greg@kroah.com, linux-serial@vger.kernel.org +Date: Mon, 26 Jul 2010 10:18:21 +0100 +Message-ID: <20100726091818.21579.67436.stgit@localhost.localdomain> + +From: Feng Tang <feng.tang@intel.com> + +A general problem for uart rx dma channel is you never know when +and how much data will be received, so usually preset it a DMA +descriptor with a big size, and rely on DMA RX timeout IRQ to +know there is some data in rx channel. + +For a RX data size of multiple of MOTSR, there will be no timeout +IRQ issued, thus OS will never be notified about that. + +This is a work around for that, current timer frequency is 5 times +per second, it should vary according to the baud rate + +When future silicon version fix the problem, this workaround need +be removed + +Signed-off-by: Feng Tang <feng.tang@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/mfd.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 47 insertions(+), 3 deletions(-) + +--- a/drivers/serial/mfd.c ++++ b/drivers/serial/mfd.c +@@ -64,6 +64,8 @@ + #define mfd_readl(obj, offset) readl(obj->reg + offset) + #define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) + ++#define HSU_DMA_TIMEOUT_CHECK_FREQ (HZ/10) ++ + struct hsu_dma_buffer { + u8 *buf; + dma_addr_t dma_addr; +@@ -75,7 +77,8 @@ struct hsu_dma_chan { + u32 id; + u32 dirt; /* to or from device */ + struct uart_hsu_port *uport; +- void __iomem *reg; ++ void __iomem *reg; ++ struct timer_list rx_timer; /* only needed by RX channel */ + }; + + struct uart_hsu_port { +@@ -377,6 +380,8 @@ void hsu_dma_start_rx_chan(struct hsu_dm + | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ + ); + chan_writel(rxc, HSU_CH_CR, 0x3); ++ ++ mod_timer(&rxc->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); + } + + /* Protected by spin_lock_irqsave(port->lock) */ +@@ -437,8 +442,13 @@ void hsu_dma_rx(struct uart_hsu_port *up + /* We can use 2 ways to calc the actual transfer len */ + count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; + +- if (!count) ++ if (!count) { ++ /* restart the channel before we leave */ ++ chan_writel(chan, HSU_CH_CR, 0x3); + return; ++ } ++ ++ del_timer(&chan->rx_timer); + + dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, + dbuf->dma_size, DMA_FROM_DEVICE); +@@ -463,9 +473,12 @@ void hsu_dma_rx(struct uart_hsu_port *up + | (0x1 << 16) + | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ + ); ++ tty_flip_buffer_push(tty); ++ + chan_writel(chan, HSU_CH_CR, 0x3); ++ chan->rx_timer.expires = jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ; ++ add_timer(&chan->rx_timer); + +- tty_flip_buffer_push(tty); + } + + static void serial_hsu_stop_rx(struct uart_port *port) +@@ -893,6 +906,8 @@ static void serial_hsu_shutdown(struct u + container_of(port, struct uart_hsu_port, port); + unsigned long flags; + ++ del_timer_sync(&up->rxc->rx_timer); ++ + /* Disable interrupts from this port */ + up->ier = 0; + serial_out(up, UART_IER, 0); +@@ -1348,6 +1363,28 @@ err_disable: + return ret; + } + ++static void hsu_dma_rx_timeout(unsigned long data) ++{ ++ struct hsu_dma_chan *chan = (void *)data; ++ struct uart_hsu_port *up = chan->uport; ++ struct hsu_dma_buffer *dbuf = &up->rxbuf; ++ int count = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; ++ ++ if (!count) { ++ mod_timer(&chan->rx_timer, jiffies + HSU_DMA_TIMEOUT_CHECK_FREQ); ++ goto exit; ++ } ++ ++ hsu_dma_rx(up, 0); ++exit: ++ spin_unlock_irqrestore(&up->port.lock, flags); ++} ++ + static void hsu_global_init(void) + { + struct hsu_port *hsu; +@@ -1409,6 +1446,13 @@ static void hsu_global_init(void) + dchan->uport = &hsu->port[i/2]; + dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + + i * HSU_DMA_CHANS_REG_LENGTH; ++ ++ /* Work around for RX */ ++ if (dchan->dirt == DMA_FROM_DEVICE) { ++ init_timer(&dchan->rx_timer); ++ dchan->rx_timer.function = hsu_dma_rx_timeout; ++ dchan->rx_timer.data = (unsigned long)dchan; ++ } + dchan++; + } + diff --git a/tty/hsu-call-pci-pm-hooks-in-suspend-resume-function.patch b/tty/hsu-call-pci-pm-hooks-in-suspend-resume-function.patch new file mode 100644 index 00000000000000..956724458e6ef7 --- /dev/null +++ b/tty/hsu-call-pci-pm-hooks-in-suspend-resume-function.patch @@ -0,0 +1,69 @@ +From alan@linux.intel.com Mon Jul 26 14:23:51 2010 +From: Alan Cox <alan@linux.intel.com> +Subject: hsu: call PCI pm hooks in suspend/resume function +To: greg@kroah.com, linux-serial@vger.kernel.org +Date: Mon, 26 Jul 2010 10:18:46 +0100 +Message-ID: <20100726091839.21579.4983.stgit@localhost.localdomain> + +From: Feng Tang <feng.tang@intel.com> + +Also add check for dma controller or the uart ports. + +Signed-off-by: Feng Tang <feng.tang@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/mfd.c | 31 ++++++++++++++++++++++--------- + 1 file changed, 22 insertions(+), 9 deletions(-) + +--- a/drivers/serial/mfd.c ++++ b/drivers/serial/mfd.c +@@ -1217,25 +1217,38 @@ static struct uart_driver serial_hsu_reg + #ifdef CONFIG_PM + static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) + { ++ void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; + +- up = pci_get_drvdata(pdev); +- if (!up) +- return 0; +- +- uart_suspend_port(&serial_hsu_reg, &up->port); ++ /* Make sure this is not the internal dma controller */ ++ if (priv && (pdev->device != 0x081E)) { ++ up = priv; ++ uart_suspend_port(&serial_hsu_reg, &up->port); ++ } + ++ pci_save_state(pdev); ++ pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; + } + + static int serial_hsu_resume(struct pci_dev *pdev) + { ++ void *priv = pci_get_drvdata(pdev); + struct uart_hsu_port *up; ++ int ret; ++ ++ pci_set_power_state(pdev, PCI_D0); ++ pci_restore_state(pdev); ++ ++ ret = pci_enable_device(pdev); ++ if (ret) ++ dev_warn(&pdev->dev, ++ "HSU: can't re-enable device, try to continue\n"); + +- up = pci_get_drvdata(pdev); +- if (!up) +- return 0; +- uart_resume_port(&serial_hsu_reg, &up->port); ++ if (priv && (pdev->device != 0x081E)) { ++ up = priv; ++ uart_resume_port(&serial_hsu_reg, &up->port); ++ } + return 0; + } + #else diff --git a/tty/hsu-driver-for-medfield-high-speed-uart-device.patch b/tty/hsu-driver-for-medfield-high-speed-uart-device.patch new file mode 100644 index 00000000000000..fe3e1747abf3b7 --- /dev/null +++ b/tty/hsu-driver-for-medfield-high-speed-uart-device.patch @@ -0,0 +1,1596 @@ +From alan@linux.intel.com Mon Jul 26 14:22:51 2010 +From: Alan Cox <alan@linux.intel.com> +Subject: hsu: driver for Medfield High Speed UART device +To: greg@kroah.com, linux-serial@vger.kernel.org +Date: Mon, 26 Jul 2010 10:18:10 +0100 +Message-ID: <20100726091803.21579.750.stgit@localhost.localdomain> + +From: Feng Tang <feng.tang@intel.com> + +This is a PCI & UART driver, which suppors both PIO and DMA mode +UART operation. It has 3 identical UART ports and one internal +DMA controller. + +Current FW will export 4 pci devices for hsu: 3 uart ports and 1 +dma controller, each has one IRQ line. And we need to discuss the +device model, one PCI device covering whole HSU should be a better +model, but there is a problem of how to export the 4 IRQs info + +Current driver set the highest baud rate to 2746800bps, which is +easy to scale down to 115200/230400.... To suport higher baud rate, +we need add special process, change DLAB/DLH/PS/DIV/MUL registers +all together. + +921600 is the highest baud rate that has been tested with Bluetooth +modem connected to HSU port 0. Will test more when there is right +BT firmware. + +Current version contains several work around for A0's Silicon bugs + +Signed-off-by: Feng Tang <feng.tang@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/Kconfig | 10 + drivers/serial/Makefile | 1 + drivers/serial/mfd.c | 1488 ++++++++++++++++++++++++++++++++++++++++++++ + include/linux/serial_core.h | 2 + include/linux/serial_reg.h | 16 + 5 files changed, 1517 insertions(+) + +--- a/drivers/serial/Kconfig ++++ b/drivers/serial/Kconfig +@@ -732,6 +732,16 @@ config MRST_MAX3110_IRQ + help + This has to be enabled after Moorestown GPIO driver is loaded + ++config SERIAL_MFD_HSU ++ tristate "Medfield High Speed UART support" ++ depends on PCI ++ select SERIAL_CORE ++ ++config SERIAL_MFD_HSU_CONSOLE ++ boolean "Medfile HSU serial console support" ++ depends on SERIAL_MFD_HSU=y ++ select SERIAL_CORE_CONSOLE ++ + config SERIAL_BFIN + tristate "Blackfin serial port support" + depends on BLACKFIN +--- a/drivers/serial/Makefile ++++ b/drivers/serial/Makefile +@@ -87,3 +87,4 @@ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUAR + obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o + obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o + obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o ++obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o +--- /dev/null ++++ b/drivers/serial/mfd.c +@@ -0,0 +1,1488 @@ ++/* ++ * mfd.c: driver for High Speed UART device of Intel Medfield platform ++ * ++ * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ ++ * ++ * (C) Copyright 2009 Intel Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; version 2 ++ * of the License. ++ */ ++ ++ ++/* Notes: ++ * 1. there should be 2 types of register access method, one for ++ * UART ports, the other for the general purpose registers ++ * ++ * 2. It used to have a Irda port, but was defeatured recently ++ * ++ * 3. Based on the info from HSU MAS, 0/1 channel are assigned to ++ * port0, 2/3 chan to port 1, 4/5 chan to port 3. Even number ++ * chan will be read, odd chan for write ++ * ++ * 4. HUS supports both the 64B and 16B FIFO version, but this driver ++ * will only use 64B version ++ * ++ * 5. In A0 stepping, UART will not support TX half empty flag, thus ++ * need add a #ifdef judgement ++ * ++ * 6. One more bug for A0, the loopback mode won't support AFC ++ * auto-flow control ++ * ++ * 7. HSU has some special FCR control bits, we add it to serial_reg.h ++ * ++ * 8. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always asserted, ++ * only when the HW is reset the DDCD and DDSR will be triggered ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/console.h> ++#include <linux/sysrq.h> ++#include <linux/serial_reg.h> ++#include <linux/circ_buf.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/tty_flip.h> ++#include <linux/serial_core.h> ++#include <linux/serial_mfd.h> ++#include <linux/dma-mapping.h> ++#include <linux/pci.h> ++#include <linux/io.h> ++#include <linux/debugfs.h> ++ ++#define MFD_HSU_A0_STEPPING 1 ++ ++#define HSU_DMA_BUF_SIZE 2048 ++ ++#define chan_readl(chan, offset) readl(chan->reg + offset) ++#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) ++ ++#define mfd_readl(obj, offset) readl(obj->reg + offset) ++#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) ++ ++struct hsu_dma_buffer { ++ u8 *buf; ++ dma_addr_t dma_addr; ++ u32 dma_size; ++ u32 ofs; ++}; ++ ++struct hsu_dma_chan { ++ u32 id; ++ u32 dirt; /* to or from device */ ++ struct uart_hsu_port *uport; ++ void __iomem *reg; ++}; ++ ++struct uart_hsu_port { ++ struct uart_port port; ++ unsigned char ier; ++ unsigned char lcr; ++ unsigned char mcr; ++ unsigned int lsr_break_flag; ++ char name[12]; ++ int index; ++ struct device *dev; ++ ++ struct hsu_dma_chan *txc; ++ struct hsu_dma_chan *rxc; ++ struct hsu_dma_buffer txbuf; ++ struct hsu_dma_buffer rxbuf; ++ int use_dma; /* flag for DMA/PIO */ ++ int running; ++ int dma_tx_on; ++}; ++ ++/* Top level data structure of HSU */ ++struct hsu_port { ++ struct pci_device *pdev; ++ ++ void __iomem *reg; ++ unsigned long paddr; ++ unsigned long iolen; ++ u32 irq; ++ ++ struct uart_hsu_port port[3]; ++ struct hsu_dma_chan chans[10]; ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *debugfs; ++#endif ++}; ++ ++static inline void hexdump(char *str, u8 *addr, int cnt) ++{ ++ int i; ++ ++ for (i = 0; i < cnt; i += 8) { ++ printk("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", ++ addr[i], addr[i+1], addr[i+2], addr[i+3], ++ addr[i+4], addr[i+5], addr[i+6], addr[i+7]); ++ printk("\n"); ++ } ++} ++ ++static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) ++{ ++ unsigned int val; ++ ++ if (offset > UART_MSR) { ++ offset <<= 2; ++ val = readl(up->port.membase + offset); ++ } else ++ val = (unsigned int)readb(up->port.membase + offset); ++ ++ return val; ++} ++ ++static inline void serial_out(struct uart_hsu_port *up, int offset, int value) ++{ ++ if (offset > UART_MSR) { ++ offset <<= 2; ++ writel(value, up->port.membase + offset); ++ } else { ++ unsigned char val = value & 0xff; ++ writeb(val, up->port.membase + offset); ++ } ++} ++ ++#ifdef CONFIG_DEBUG_FS ++ ++#define HSU_REGS_BUFSIZE 1024 ++ ++static int hsu_show_regs_open(struct inode *inode, struct file *file) ++{ ++ file->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t port_show_regs(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct uart_hsu_port *up = file->private_data; ++ char *buf; ++ u32 len = 0; ++ ssize_t ret; ++ ++ buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); ++ if (!buf) ++ return 0; ++ ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MFD HSU port[%d] regs:\n", up->index); ++ ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "=================================\n"); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ return ret; ++} ++ ++static ssize_t dma_show_regs(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct hsu_dma_chan *chan = file->private_data; ++ char *buf; ++ u32 len = 0; ++ ssize_t ret; ++ ++ buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); ++ if (!buf) ++ return 0; ++ ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MFD HSU DMA channel [%d] regs:\n", chan->id); ++ ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "=================================\n"); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); ++ len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, ++ "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); ++ ++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); ++ kfree(buf); ++ return ret; ++} ++ ++static const struct file_operations port_regs_ops = { ++ .owner = THIS_MODULE, ++ .open = hsu_show_regs_open, ++ .read = port_show_regs, ++}; ++ ++static const struct file_operations dma_regs_ops = { ++ .owner = THIS_MODULE, ++ .open = hsu_show_regs_open, ++ .read = dma_show_regs, ++}; ++ ++static int hsu_debugfs_init(struct hsu_port *hsu) ++{ ++ int i; ++ char name[32]; ++ ++ hsu->debugfs = debugfs_create_dir("hsu", NULL); ++ if (!hsu->debugfs) ++ return -ENOMEM; ++ ++ for (i = 0; i < 3; i++) { ++ snprintf(name, sizeof(name), "port_%d_regs", i); ++ debugfs_create_file(name, S_IFREG | S_IRUGO, ++ hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); ++ } ++ ++ for (i = 0; i < 6; i++) { ++ snprintf(name, sizeof(name), "dma_chan_%d_regs", i); ++ debugfs_create_file(name, S_IFREG | S_IRUGO, ++ hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); ++ } ++ ++ return 0; ++} ++ ++static void hsu_debugfs_remove(struct hsu_port *hsu) ++{ ++ if (hsu->debugfs) ++ debugfs_remove_recursive(hsu->debugfs); ++} ++ ++#else ++static inline int hsu_debugfs_init(struct hsu_port *hsu) ++{ ++ return 0; ++} ++ ++static inline void hsu_debugfs_remove(struct hsu_port *hsu) ++{ ++} ++#endif /* CONFIG_DEBUG_FS */ ++ ++static void serial_hsu_enable_ms(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ ++ up->ier |= UART_IER_MSI; ++ serial_out(up, UART_IER, up->ier); ++} ++ ++void hsu_dma_tx(struct uart_hsu_port *up) ++{ ++ struct circ_buf *xmit = &up->port.state->xmit; ++ struct hsu_dma_buffer *dbuf = &up->txbuf; ++ int count; ++ ++ /* test_and_set_bit may be better, but anyway it's in lock protected mode */ ++ if (up->dma_tx_on) ++ return; ++ ++ /* Update the circ buf info */ ++ xmit->tail += dbuf->ofs; ++ xmit->tail &= UART_XMIT_SIZE - 1; ++ ++ up->port.icount.tx += dbuf->ofs; ++ dbuf->ofs = 0; ++ ++ /* Disable the channel */ ++ chan_writel(up->txc, HSU_CH_CR, 0x0); ++ ++ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { ++ dma_sync_single_for_device(up->port.dev, ++ dbuf->dma_addr, ++ dbuf->dma_size, ++ DMA_TO_DEVICE); ++ ++ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); ++ dbuf->ofs = count; ++ ++ /* Reprogram the channel */ ++ chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); ++ chan_writel(up->txc, HSU_CH_D0TSR, count); ++ ++ /* Reenable the channel */ ++ chan_writel(up->txc, HSU_CH_DCR, 0x1 ++ | (0x1 << 8) ++ | (0x1 << 16) ++ | (0x1 << 24)); ++ ++ WARN(chan_readl(up->txc, HSU_CH_CR) & 0x1, ++ "TX channel has already be started!!\n"); ++ up->dma_tx_on = 1; ++ chan_writel(up->txc, HSU_CH_CR, 0x1); ++ } ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(&up->port); ++} ++ ++/* The buffer is already cache coherent */ ++void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) ++{ ++ /* Need start RX dma channel here */ ++ dbuf->ofs = 0; ++ ++ chan_writel(rxc, HSU_CH_BSR, 32); ++ chan_writel(rxc, HSU_CH_MOTSR, 4); ++ ++ chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); ++ chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); ++ chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) ++ | (0x1 << 16) ++ | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ ++ ); ++ chan_writel(rxc, HSU_CH_CR, 0x3); ++} ++ ++/* Protected by spin_lock_irqsave(port->lock) */ ++static void serial_hsu_start_tx(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ ++ if (up->use_dma) { ++ hsu_dma_tx(up); ++ } else if (!(up->ier & UART_IER_THRI)) { ++ up->ier |= UART_IER_THRI; ++ serial_out(up, UART_IER, up->ier); ++ } ++} ++ ++static void serial_hsu_stop_tx(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ struct hsu_dma_chan *txc = up->txc; ++ ++ if (up->use_dma) ++ chan_writel(txc, HSU_CH_CR, 0x0); ++ else if (up->ier & UART_IER_THRI) { ++ up->ier &= ~UART_IER_THRI; ++ serial_out(up, UART_IER, up->ier); ++ } ++} ++ ++/* This is always called in spinlock protected mode, so ++ * modify timeout timer is safe here */ ++void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts) ++{ ++ struct hsu_dma_buffer *dbuf = &up->rxbuf; ++ struct hsu_dma_chan *chan = up->rxc; ++ struct uart_port *port = &up->port; ++ struct tty_struct *tty = port->state->port.tty; ++ int count; ++ ++ if (!tty) ++ return; ++ ++ /* ++ * first need to know how many is already transferred, ++ * then check if its a timeout DMA irq, and return ++ * the trail bytes out, push them up and reenable the ++ * channel, better to use 2 descriptors at the same time ++ */ ++ ++ /* timeout IRQ, need wait some time, see Errata 2 */ ++ if (int_sts & 0xf00) ++ udelay(2); ++ ++ /* Stop the channel */ ++ chan_writel(chan, HSU_CH_CR, 0x0); ++ ++ /* We can use 2 ways to calc the actual transfer len */ ++ count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; ++ ++ if (!count) ++ return; ++ ++ dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, ++ dbuf->dma_size, DMA_FROM_DEVICE); ++ ++ /* ++ * head will only wrap around when we recycle ++ * the DMA buffer, and when that happens, we ++ * explicitly set tail to 0. So head will ++ * always be greater than tail. ++ */ ++ tty_insert_flip_string(tty, dbuf->buf, count); ++ port->icount.rx += count; ++ ++ dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, ++ dbuf->dma_size, DMA_FROM_DEVICE); ++ ++ /* Reprogram the channel */ ++ chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); ++ chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); ++ chan_writel(chan, HSU_CH_DCR, 0x1 ++ | (0x1 << 8) ++ | (0x1 << 16) ++ | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ ++ ); ++ chan_writel(chan, HSU_CH_CR, 0x3); ++ ++ tty_flip_buffer_push(tty); ++} ++ ++static void serial_hsu_stop_rx(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ struct hsu_dma_chan *chan = up->rxc; ++ ++ if (up->use_dma) ++ chan_writel(chan, HSU_CH_CR, 0x2); ++ else { ++ up->ier &= ~UART_IER_RLSI; ++ up->port.read_status_mask &= ~UART_LSR_DR; ++ serial_out(up, UART_IER, up->ier); ++ } ++} ++ ++/* ++ * if there is error flag, should we just reset the FIFO or keeps ++ * working on it ++ */ ++static inline void receive_chars(struct uart_hsu_port *up, int *status) ++{ ++ struct tty_struct *tty = up->port.state->port.tty; ++ unsigned int ch, flag; ++ unsigned int max_count = 256; ++ ++ if (!tty) ++ return; ++ ++ do { ++ ch = serial_in(up, UART_RX); ++ flag = TTY_NORMAL; ++ up->port.icount.rx++; ++ ++ if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | ++ UART_LSR_FE | UART_LSR_OE))) { ++ ++ dev_warn(up->dev, "We really rush into ERR/BI case" ++ "status = 0x%02x", *status); ++ /* For statistics only */ ++ if (*status & UART_LSR_BI) { ++ *status &= ~(UART_LSR_FE | UART_LSR_PE); ++ up->port.icount.brk++; ++ /* ++ * We do the SysRQ and SAK checking ++ * here because otherwise the break ++ * may get masked by ignore_status_mask ++ * or read_status_mask. ++ */ ++ if (uart_handle_break(&up->port)) ++ goto ignore_char; ++ } else if (*status & UART_LSR_PE) ++ up->port.icount.parity++; ++ else if (*status & UART_LSR_FE) ++ up->port.icount.frame++; ++ if (*status & UART_LSR_OE) ++ up->port.icount.overrun++; ++ ++ /* Mask off conditions which should be ignored. */ ++ *status &= up->port.read_status_mask; ++ ++#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE ++ if (up->port.cons && ++ up->port.cons->index == up->port.line) { ++ /* Recover the break flag from console xmit */ ++ *status |= up->lsr_break_flag; ++ up->lsr_break_flag = 0; ++ } ++#endif ++ if (*status & UART_LSR_BI) { ++ flag = TTY_BREAK; ++ } else if (*status & UART_LSR_PE) ++ flag = TTY_PARITY; ++ else if (*status & UART_LSR_FE) ++ flag = TTY_FRAME; ++ } ++ ++ if (uart_handle_sysrq_char(&up->port, ch)) ++ goto ignore_char; ++ ++ uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); ++ ignore_char: ++ *status = serial_in(up, UART_LSR); ++ } while ((*status & UART_LSR_DR) && max_count--); ++ tty_flip_buffer_push(tty); ++} ++ ++static void transmit_chars(struct uart_hsu_port *up) ++{ ++ struct circ_buf *xmit = &up->port.state->xmit; ++ int count; ++ int i = 0; /* for debug use */ ++ ++ if (up->port.x_char) { ++ serial_out(up, UART_TX, up->port.x_char); ++ up->port.icount.tx++; ++ up->port.x_char = 0; ++ return; ++ } ++ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { ++ serial_hsu_stop_tx(&up->port); ++ return; ++ } ++ ++#ifndef MFD_HSU_A0_STEPPING ++ count = up->port.fifosize / 2; ++#else ++ /* ++ * A0 only supports fully empty IRQ, and the first char written ++ * into it won't clear the EMPT bit, so we may need be cautious ++ * by useing a shorter buffer ++ */ ++ /* count = up->port.fifosize; */ ++ count = up->port.fifosize - 4; ++#endif ++ do { ++ serial_out(up, UART_TX, xmit->buf[xmit->tail]); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ i++; ++ ++ up->port.icount.tx++; ++ if (uart_circ_empty(xmit)) ++ break; ++ } while (--count > 0); ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(&up->port); ++ ++ if (uart_circ_empty(xmit)) ++ serial_hsu_stop_tx(&up->port); ++} ++ ++static inline void check_modem_status(struct uart_hsu_port *up) ++{ ++ int status; ++ ++ status = serial_in(up, UART_MSR); ++ ++ if ((status & UART_MSR_ANY_DELTA) == 0) ++ return; ++ ++ if (status & UART_MSR_TERI) ++ up->port.icount.rng++; ++ if (status & UART_MSR_DDSR) ++ up->port.icount.dsr++; ++ /* We may only get DDCD when HW init and reset */ ++ if (status & UART_MSR_DDCD) ++ uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); ++ /* will start/stop_tx accordingly */ ++ if (status & UART_MSR_DCTS) ++ uart_handle_cts_change(&up->port, status & UART_MSR_CTS); ++ ++ wake_up_interruptible(&up->port.state->port.delta_msr_wait); ++} ++ ++/* ++ * This handles the interrupt from one port. ++ */ ++static irqreturn_t port_irq(int irq, void *dev_id) ++{ ++ struct uart_hsu_port *up = dev_id; ++ unsigned int iir, lsr; ++ unsigned long flags; ++ ++ if (unlikely(!up->running)) ++ return IRQ_NONE; ++ ++ if (up->use_dma) { ++ lsr = serial_in(up, UART_LSR); ++ if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | ++ UART_LSR_FE | UART_LSR_OE))) ++ dev_warn(up->dev, ++ "Got lsr irq while using DMA, lsr = 0x%2x\n", ++ lsr); ++ check_modem_status(up); ++ return IRQ_HANDLED; ++ } ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ iir = serial_in(up, UART_IIR); ++ if (iir & UART_IIR_NO_INT) { ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ return IRQ_NONE; ++ } ++ ++ lsr = serial_in(up, UART_LSR); ++ ++ if (lsr & UART_LSR_DR) ++ receive_chars(up, &lsr); ++ ++ /* lsr will be renewed during the receive_chars */ ++ if (lsr & UART_LSR_THRE) ++ transmit_chars(up); ++ ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ return IRQ_HANDLED; ++} ++ ++static inline void dma_chan_irq(struct hsu_dma_chan *chan) ++{ ++ struct uart_hsu_port *up = chan->uport; ++ unsigned long flags; ++ u32 int_sts; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ if (!up->use_dma || !up->running) ++ goto exit; ++ ++ /* ++ * No matter what situation, need read clear the IRQ status ++ * There is a bug, see Errata 5, HSD 2900918 ++ */ ++ int_sts = chan_readl(chan, HSU_CH_SR); ++ ++ /* Rx channel */ ++ if (chan->dirt == DMA_FROM_DEVICE) ++ hsu_dma_rx(up, int_sts); ++ ++ /* Tx channel */ ++ if (chan->dirt == DMA_TO_DEVICE) { ++ /* dma for irq should be done */ ++ chan_writel(chan, HSU_CH_CR, 0x0); ++ up->dma_tx_on = 0; ++ hsu_dma_tx(up); ++ } ++ ++exit: ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ return; ++} ++ ++static irqreturn_t dma_irq(int irq, void *dev_id) ++{ ++ struct hsu_port *hsu = dev_id; ++ u32 int_sts, i; ++ ++ int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); ++ ++ /* Currently we only have 6 channels may be used */ ++ for (i = 0; i < 6; i++) { ++ if (int_sts & 0x1) ++ dma_chan_irq(&hsu->chans[i]); ++ int_sts >>= 1; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static unsigned int serial_hsu_tx_empty(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned long flags; ++ unsigned int ret; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ return ret; ++} ++ ++static unsigned int serial_hsu_get_mctrl(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned char status; ++ unsigned int ret; ++ ++ status = serial_in(up, UART_MSR); ++ ++ ret = 0; ++ if (status & UART_MSR_DCD) ++ ret |= TIOCM_CAR; ++ if (status & UART_MSR_RI) ++ ret |= TIOCM_RNG; ++ if (status & UART_MSR_DSR) ++ ret |= TIOCM_DSR; ++ if (status & UART_MSR_CTS) ++ ret |= TIOCM_CTS; ++ return ret; ++} ++ ++static void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned char mcr = 0; ++ ++ if (mctrl & TIOCM_RTS) ++ mcr |= UART_MCR_RTS; ++ if (mctrl & TIOCM_DTR) ++ mcr |= UART_MCR_DTR; ++ if (mctrl & TIOCM_OUT1) ++ mcr |= UART_MCR_OUT1; ++ if (mctrl & TIOCM_OUT2) ++ mcr |= UART_MCR_OUT2; ++ if (mctrl & TIOCM_LOOP) ++ mcr |= UART_MCR_LOOP; ++ ++ mcr |= up->mcr; ++ ++ serial_out(up, UART_MCR, mcr); ++} ++ ++static void serial_hsu_break_ctl(struct uart_port *port, int break_state) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ if (break_state == -1) ++ up->lcr |= UART_LCR_SBC; ++ else ++ up->lcr &= ~UART_LCR_SBC; ++ serial_out(up, UART_LCR, up->lcr); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++} ++ ++/* ++ * What special to do: ++ * 1. chose the 64B fifo mode ++ * 2. make sure not to select half empty mode for A0 stepping ++ * 3. start dma or pio depends on configuration ++ * 4. we only allocate dma memory when needed ++ */ ++static int serial_hsu_startup(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned long flags; ++ ++ /* ++ * Clear the FIFO buffers and disable them. ++ * (they will be reenabled in set_termios()) ++ */ ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | ++ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); ++ serial_out(up, UART_FCR, 0); ++ ++ /* Clear the interrupt registers. */ ++ (void) serial_in(up, UART_LSR); ++ (void) serial_in(up, UART_RX); ++ (void) serial_in(up, UART_IIR); ++ (void) serial_in(up, UART_MSR); ++ ++ /* Now, initialize the UART, default is 8n1 */ ++ serial_out(up, UART_LCR, UART_LCR_WLEN8); ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ up->port.mctrl |= TIOCM_OUT2; ++ serial_hsu_set_mctrl(&up->port, up->port.mctrl); ++ ++ /* ++ * Finally, enable interrupts. Note: Modem status interrupts ++ * are set via set_termios(), which will be occurring imminently ++ * anyway, so we don't enable them here. ++ */ ++ if (!up->use_dma) ++ up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; ++ else ++ up->ier = 0; ++ serial_out(up, UART_IER, up->ier); ++ ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ /* DMA init */ ++ /* When use DMA, TX/RX's FIFO and IRQ should be disabled */ ++ if (up->use_dma) { ++ struct hsu_dma_buffer *dbuf; ++ struct circ_buf *xmit = &port->state->xmit; ++ ++ up->dma_tx_on = 0; ++ ++ /* First allocate the RX buffer */ ++ dbuf = &up->rxbuf; ++ dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); ++ if (!dbuf->buf) { ++ up->use_dma = 0; ++ goto exit; ++ } ++ dbuf->dma_addr = dma_map_single(port->dev, ++ dbuf->buf, ++ HSU_DMA_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ dbuf->dma_size = HSU_DMA_BUF_SIZE; ++ ++ /* Start the RX channel right now */ ++ hsu_dma_start_rx_chan(up->rxc, dbuf); ++ ++ /* Next init the TX DMA */ ++ dbuf = &up->txbuf; ++ dbuf->buf = xmit->buf; ++ dbuf->dma_addr = dma_map_single(port->dev, ++ dbuf->buf, ++ UART_XMIT_SIZE, ++ DMA_TO_DEVICE); ++ dbuf->dma_size = UART_XMIT_SIZE; ++ ++ /* This should not be changed all around */ ++ chan_writel(up->txc, HSU_CH_BSR, 32); ++ chan_writel(up->txc, HSU_CH_MOTSR, 4); ++ dbuf->ofs = 0; ++ } ++ ++exit: ++ /* And clear the interrupt registers again for luck. */ ++ (void) serial_in(up, UART_LSR); ++ (void) serial_in(up, UART_RX); ++ (void) serial_in(up, UART_IIR); ++ (void) serial_in(up, UART_MSR); ++ ++ up->running = 1; ++ return 0; ++} ++ ++static void serial_hsu_shutdown(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ unsigned long flags; ++ ++ /* Disable interrupts from this port */ ++ up->ier = 0; ++ serial_out(up, UART_IER, 0); ++ up->running = 0; ++ ++ spin_lock_irqsave(&up->port.lock, flags); ++ up->port.mctrl &= ~TIOCM_OUT2; ++ serial_hsu_set_mctrl(&up->port, up->port.mctrl); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++ ++ /* Disable break condition and FIFOs */ ++ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); ++ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | ++ UART_FCR_CLEAR_RCVR | ++ UART_FCR_CLEAR_XMIT); ++ serial_out(up, UART_FCR, 0); ++} ++ ++static void ++serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, ++ struct ktermios *old) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ struct tty_struct *tty = port->state->port.tty; ++ unsigned char cval, fcr = 0; ++ unsigned long flags; ++ unsigned int baud, quot; ++ u32 mul = 0x3600; ++ u32 ps = 0x10; ++ ++ switch (termios->c_cflag & CSIZE) { ++ case CS5: ++ cval = UART_LCR_WLEN5; ++ break; ++ case CS6: ++ cval = UART_LCR_WLEN6; ++ break; ++ case CS7: ++ cval = UART_LCR_WLEN7; ++ break; ++ default: ++ case CS8: ++ cval = UART_LCR_WLEN8; ++ break; ++ } ++ ++ /* CMSPAR isn't supported by this driver */ ++ if (tty) ++ tty->termios->c_cflag &= ~CMSPAR; ++ ++ if (termios->c_cflag & CSTOPB) ++ cval |= UART_LCR_STOP; ++ if (termios->c_cflag & PARENB) ++ cval |= UART_LCR_PARITY; ++ if (!(termios->c_cflag & PARODD)) ++ cval |= UART_LCR_EPAR; ++ ++ /* ++ * For those basic low baud rate we can get the direct ++ * scalar from 2746800, like 115200 = 2746800/24, for those ++ * higher baud rate, we have to handle them case by case, ++ * but DIV reg is never touched as its default value 0x3d09 ++ */ ++ baud = uart_get_baud_rate(port, termios, old, 0, 4000000); ++ quot = uart_get_divisor(port, baud); ++ ++ switch (baud) { ++ case 3500000: ++ mul = 0x3345; ++ ps = 0xC; ++ quot = 1; ++ break; ++ case 2500000: ++ mul = 0x2710; ++ ps = 0x10; ++ quot = 1; ++ break; ++ case 18432000: ++ mul = 0x2400; ++ ps = 0x10; ++ quot = 1; ++ break; ++ case 1500000: ++ mul = 0x1D4C; ++ ps = 0xc; ++ quot = 1; ++ break; ++ default: ++ ; ++ } ++ ++ if ((up->port.uartclk / quot) < (2400 * 16)) ++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; ++ else if ((up->port.uartclk / quot) < (230400 * 16)) ++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; ++ else ++ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; ++ ++ fcr |= UART_FCR_HSU_64B_FIFO; ++#ifdef MFD_HSU_A0_STEPPING ++ /* A0 doesn't support half empty IRQ */ ++ fcr |= UART_FCR_FULL_EMPT_TXI; ++#endif ++ ++ /* ++ * Ok, we're now changing the port state. Do it with ++ * interrupts disabled. ++ */ ++ spin_lock_irqsave(&up->port.lock, flags); ++ ++ /* Update the per-port timeout */ ++ uart_update_timeout(port, termios->c_cflag, baud); ++ ++ up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; ++ if (termios->c_iflag & INPCK) ++ up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; ++ if (termios->c_iflag & (BRKINT | PARMRK)) ++ up->port.read_status_mask |= UART_LSR_BI; ++ ++ /* Characters to ignore */ ++ up->port.ignore_status_mask = 0; ++ if (termios->c_iflag & IGNPAR) ++ up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; ++ if (termios->c_iflag & IGNBRK) { ++ up->port.ignore_status_mask |= UART_LSR_BI; ++ /* ++ * If we're ignoring parity and break indicators, ++ * ignore overruns too (for real raw support). ++ */ ++ if (termios->c_iflag & IGNPAR) ++ up->port.ignore_status_mask |= UART_LSR_OE; ++ } ++ ++ /* Ignore all characters if CREAD is not set */ ++ if ((termios->c_cflag & CREAD) == 0) ++ up->port.ignore_status_mask |= UART_LSR_DR; ++ ++ /* ++ * CTS flow control flag and modem status interrupts, disable ++ * MSI by default ++ */ ++ up->ier &= ~UART_IER_MSI; ++ if (UART_ENABLE_MS(&up->port, termios->c_cflag)) ++ up->ier |= UART_IER_MSI; ++ ++ serial_out(up, UART_IER, up->ier); ++ ++ if (termios->c_cflag & CRTSCTS) ++ up->mcr |= UART_MCR_AFE | UART_MCR_RTS; ++ else ++ up->mcr &= ~UART_MCR_AFE; ++ ++ serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ ++ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ ++ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ ++ serial_out(up, UART_LCR, cval); /* reset DLAB */ ++ serial_out(up, UART_MUL, mul); /* set MUL */ ++ serial_out(up, UART_PS, ps); /* set PS */ ++ up->lcr = cval; /* Save LCR */ ++ serial_hsu_set_mctrl(&up->port, up->port.mctrl); ++ serial_out(up, UART_FCR, fcr); ++ spin_unlock_irqrestore(&up->port.lock, flags); ++} ++ ++static void ++serial_hsu_pm(struct uart_port *port, unsigned int state, ++ unsigned int oldstate) ++{ ++} ++ ++static void serial_hsu_release_port(struct uart_port *port) ++{ ++} ++ ++static int serial_hsu_request_port(struct uart_port *port) ++{ ++ return 0; ++} ++ ++static void serial_hsu_config_port(struct uart_port *port, int flags) ++{ ++#if 0 ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ up->port.type = PORT_MFD; ++#endif ++} ++ ++static int ++serial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) ++{ ++ /* We don't want the core code to modify any port params */ ++ return -EINVAL; ++} ++ ++static const char * ++serial_hsu_type(struct uart_port *port) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ return up->name; ++} ++ ++/* Mainly for uart console use */ ++static struct uart_hsu_port *serial_hsu_ports[3]; ++static struct uart_driver serial_hsu_reg; ++ ++#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE ++ ++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) ++ ++/* Wait for transmitter & holding register to empty */ ++static inline void wait_for_xmitr(struct uart_hsu_port *up) ++{ ++ unsigned int status, tmout = 1000; ++ ++ /* Wait up to 1ms for the character to be sent. */ ++ do { ++ status = serial_in(up, UART_LSR); ++ ++ if (status & UART_LSR_BI) ++ up->lsr_break_flag = UART_LSR_BI; ++ ++ if (--tmout == 0) ++ break; ++ udelay(1); ++ } while (!(status & BOTH_EMPTY)); ++ ++ /* Wait up to 1s for flow control if necessary */ ++ if (up->port.flags & UPF_CONS_FLOW) { ++ tmout = 1000000; ++ while (--tmout && ++ ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) ++ udelay(1); ++ } ++} ++ ++static void serial_hsu_console_putchar(struct uart_port *port, int ch) ++{ ++ struct uart_hsu_port *up = ++ container_of(port, struct uart_hsu_port, port); ++ ++ wait_for_xmitr(up); ++ serial_out(up, UART_TX, ch); ++} ++ ++/* ++ * Print a string to the serial port trying not to disturb ++ * any possible real use of the port... ++ * ++ * The console_lock must be held when we get here. ++ */ ++static void ++serial_hsu_console_write(struct console *co, const char *s, unsigned int count) ++{ ++ struct uart_hsu_port *up = serial_hsu_ports[co->index]; ++ unsigned long flags; ++ unsigned int ier; ++ int locked = 1; ++ ++ local_irq_save(flags); ++ if (up->port.sysrq) ++ locked = 0; ++ else if (oops_in_progress) { ++ locked = spin_trylock(&up->port.lock); ++ } else ++ spin_lock(&up->port.lock); ++ ++ /* First save the IER then disable the interrupts */ ++ ier = serial_in(up, UART_IER); ++ serial_out(up, UART_IER, 0); ++ ++ uart_console_write(&up->port, s, count, serial_hsu_console_putchar); ++ ++ /* ++ * Finally, wait for transmitter to become empty ++ * and restore the IER ++ */ ++ wait_for_xmitr(up); ++ serial_out(up, UART_IER, ier); ++ ++ if (locked) ++ spin_unlock(&up->port.lock); ++ local_irq_restore(flags); ++} ++ ++static struct console serial_hsu_console; ++ ++static int __init ++serial_hsu_console_setup(struct console *co, char *options) ++{ ++ struct uart_hsu_port *up; ++ int baud = 115200; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++ int ret; ++ ++ if (co->index == -1 || co->index >= serial_hsu_reg.nr) ++ co->index = 0; ++ up = serial_hsu_ports[co->index]; ++ if (!up) ++ return -ENODEV; ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ ++ ret = uart_set_options(&up->port, co, baud, parity, bits, flow); ++ ++ return ret; ++} ++ ++static struct console serial_hsu_console = { ++ .name = "ttyMFD", ++ .write = serial_hsu_console_write, ++ .device = uart_console_device, ++ .setup = serial_hsu_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = 2, ++ .data = &serial_hsu_reg, ++}; ++#endif ++ ++struct uart_ops serial_hsu_pops = { ++ .tx_empty = serial_hsu_tx_empty, ++ .set_mctrl = serial_hsu_set_mctrl, ++ .get_mctrl = serial_hsu_get_mctrl, ++ .stop_tx = serial_hsu_stop_tx, ++ .start_tx = serial_hsu_start_tx, ++ .stop_rx = serial_hsu_stop_rx, ++ .enable_ms = serial_hsu_enable_ms, ++ .break_ctl = serial_hsu_break_ctl, ++ .startup = serial_hsu_startup, ++ .shutdown = serial_hsu_shutdown, ++ .set_termios = serial_hsu_set_termios, ++ .pm = serial_hsu_pm, ++ .type = serial_hsu_type, ++ .release_port = serial_hsu_release_port, ++ .request_port = serial_hsu_request_port, ++ .config_port = serial_hsu_config_port, ++ .verify_port = serial_hsu_verify_port, ++}; ++ ++static struct uart_driver serial_hsu_reg = { ++ .owner = THIS_MODULE, ++ .driver_name = "MFD serial", ++ .dev_name = "ttyMFD", ++ .major = TTY_MAJOR, ++ .minor = 128, ++ .nr = 3, ++}; ++ ++#ifdef CONFIG_PM ++static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct uart_hsu_port *up; ++ ++ up = pci_get_drvdata(pdev); ++ if (!up) ++ return 0; ++ ++ uart_suspend_port(&serial_hsu_reg, &up->port); ++ ++ return 0; ++} ++ ++static int serial_hsu_resume(struct pci_dev *pdev) ++{ ++ struct uart_hsu_port *up; ++ ++ up = pci_get_drvdata(pdev); ++ if (!up) ++ return 0; ++ uart_resume_port(&serial_hsu_reg, &up->port); ++ return 0; ++} ++#else ++#define serial_hsu_suspend NULL ++#define serial_hsu_resume NULL ++#endif ++ ++/* temp global pointer before we settle down on using one or four PCI dev */ ++static struct hsu_port *phsu; ++ ++static int serial_hsu_probe(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct uart_hsu_port *uport; ++ int index, ret; ++ ++ printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", ++ pdev->vendor, pdev->device); ++ ++ switch (pdev->device) { ++ case 0x081B: ++ index = 0; ++ break; ++ case 0x081C: ++ index = 1; ++ break; ++ case 0x081D: ++ index = 2; ++ break; ++ case 0x081E: ++ /* internal DMA controller */ ++ index = 3; ++ break; ++ default: ++ dev_err(&pdev->dev, "HSU: out of index!"); ++ return -ENODEV; ++ } ++ ++ ret = pci_enable_device(pdev); ++ if (ret) ++ return ret; ++ ++ if (index == 3) { ++ /* DMA controller */ ++ ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); ++ if (ret) { ++ dev_err(&pdev->dev, "can not get IRQ\n"); ++ goto err_disable; ++ } ++ pci_set_drvdata(pdev, phsu); ++ } else { ++ /* UART port 0~2 */ ++ uport = &phsu->port[index]; ++ uport->port.irq = pdev->irq; ++ uport->port.dev = &pdev->dev; ++ uport->dev = &pdev->dev; ++ ++ ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); ++ if (ret) { ++ dev_err(&pdev->dev, "can not get IRQ\n"); ++ goto err_disable; ++ } ++ uart_add_one_port(&serial_hsu_reg, &uport->port); ++ ++#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE ++ if (index == 2) { ++ register_console(&serial_hsu_console); ++ uport->port.cons = &serial_hsu_console; ++ } ++#endif ++ pci_set_drvdata(pdev, uport); ++ } ++ ++ return 0; ++ ++err_disable: ++ pci_disable_device(pdev); ++ return ret; ++} ++ ++static void hsu_global_init(void) ++{ ++ struct hsu_port *hsu; ++ struct uart_hsu_port *uport; ++ struct hsu_dma_chan *dchan; ++ int i, ret; ++ ++ hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); ++ if (!hsu) ++ return; ++ ++ /* Get basic io resource and map it */ ++ hsu->paddr = 0xffa28000; ++ hsu->iolen = 0x1000; ++ ++ if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) ++ pr_warning("HSU: error in request mem region\n"); ++ ++ hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); ++ if (!hsu->reg) { ++ pr_err("HSU: error in ioremap\n"); ++ ret = -ENOMEM; ++ goto err_free_region; ++ } ++ ++ /* Initialise the 3 UART ports */ ++ uport = hsu->port; ++ for (i = 0; i < 3; i++) { ++ uport->port.type = PORT_MFD; ++ uport->port.iotype = UPIO_MEM; ++ uport->port.mapbase = (resource_size_t)hsu->paddr ++ + HSU_PORT_REG_OFFSET ++ + i * HSU_PORT_REG_LENGTH; ++ uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET ++ + i * HSU_PORT_REG_LENGTH; ++ ++ sprintf(uport->name, "hsu_port%d", i); ++ uport->port.fifosize = 64; ++ uport->port.ops = &serial_hsu_pops; ++ uport->port.line = i; ++ uport->port.flags = UPF_IOREMAP; ++ /* make the maxim support rate to 2746800 bps */ ++ uport->port.uartclk = 115200 * 24 * 16; ++ ++ uport->running = 0; ++ uport->txc = &hsu->chans[i * 2]; ++ uport->rxc = &hsu->chans[i * 2 + 1]; ++ ++ serial_hsu_ports[i] = uport; ++ uport->index = i; ++ uport++; ++ } ++ ++ /* Initialise 6 dma channels */ ++ dchan = hsu->chans; ++ for (i = 0; i < 6; i++) { ++ dchan->id = i; ++ dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; ++ dchan->uport = &hsu->port[i/2]; ++ dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + ++ i * HSU_DMA_CHANS_REG_LENGTH; ++ dchan++; ++ } ++ ++ phsu = hsu; ++ ++ hsu_debugfs_init(hsu); ++ return; ++ ++err_free_region: ++ release_mem_region(hsu->paddr, hsu->iolen); ++ kfree(hsu); ++ return; ++} ++ ++static void serial_hsu_remove(struct pci_dev *pdev) ++{ ++ struct hsu_port *hsu; ++ int i; ++ ++ hsu = pci_get_drvdata(pdev); ++ if (!hsu) ++ return; ++ ++ for (i = 0; i < 3; i++) ++ uart_remove_one_port(&serial_hsu_reg, &hsu->port[i].port); ++ ++ pci_set_drvdata(pdev, NULL); ++ free_irq(hsu->irq, hsu); ++ pci_disable_device(pdev); ++} ++ ++/* First 3 are UART ports, and the 4th is the DMA */ ++static const struct pci_device_id pci_ids[] __devinitdata = { ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, ++ {}, ++}; ++ ++static struct pci_driver hsu_pci_driver = { ++ .name = "HSU serial", ++ .id_table = pci_ids, ++ .probe = serial_hsu_probe, ++ .remove = __devexit_p(serial_hsu_remove), ++ .suspend = serial_hsu_suspend, ++ .resume = serial_hsu_resume, ++}; ++ ++static int __init hsu_pci_init(void) ++{ ++ int ret; ++ ++ hsu_global_init(); ++ ++ ret = uart_register_driver(&serial_hsu_reg); ++ if (ret) ++ return ret; ++ ++ return pci_register_driver(&hsu_pci_driver); ++} ++ ++static void __exit hsu_pci_exit(void) ++{ ++ pci_unregister_driver(&hsu_pci_driver); ++ uart_unregister_driver(&serial_hsu_reg); ++ ++ hsu_debugfs_remove(phsu); ++ ++ kfree(phsu); ++} ++ ++module_init(hsu_pci_init); ++module_exit(hsu_pci_exit); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:medfield-hsu"); +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -189,6 +189,8 @@ + /* MAX3107 */ + #define PORT_MAX3107 94 + ++/* High Speed UART for Medfield */ ++#define PORT_MFD 95 + + #ifdef __KERNEL__ + +--- a/include/linux/serial_reg.h ++++ b/include/linux/serial_reg.h +@@ -221,8 +221,24 @@ + #define UART_FCR_PXAR16 0x80 /* receive FIFO threshold = 16 */ + #define UART_FCR_PXAR32 0xc0 /* receive FIFO threshold = 32 */ + ++/* ++ * Intel MID on-chip HSU (High Speed UART) defined bits ++ */ ++#define UART_FCR_HSU_64_1B 0x00 /* receive FIFO treshold = 1 */ ++#define UART_FCR_HSU_64_16B 0x40 /* receive FIFO treshold = 16 */ ++#define UART_FCR_HSU_64_32B 0x80 /* receive FIFO treshold = 32 */ ++#define UART_FCR_HSU_64_56B 0xc0 /* receive FIFO treshold = 56 */ ++ ++#define UART_FCR_HSU_16_1B 0x00 /* receive FIFO treshold = 1 */ ++#define UART_FCR_HSU_16_4B 0x40 /* receive FIFO treshold = 4 */ ++#define UART_FCR_HSU_16_8B 0x80 /* receive FIFO treshold = 8 */ ++#define UART_FCR_HSU_16_14B 0xc0 /* receive FIFO treshold = 14 */ + ++#define UART_FCR_HSU_64B_FIFO 0x20 /* chose 64 bytes FIFO */ ++#define UART_FCR_HSU_16B_FIFO 0x00 /* chose 16 bytes FIFO */ + ++#define UART_FCR_HALF_EMPT_TXI 0x00 /* trigger TX_EMPT IRQ for half empty */ ++#define UART_FCR_FULL_EMPT_TXI 0x08 /* trigger TX_EMPT IRQ for full empty */ + + /* + * These register definitions are for the 16C950 diff --git a/tty/hsu-some-code-cleanup.patch b/tty/hsu-some-code-cleanup.patch new file mode 100644 index 00000000000000..360a8e9170bead --- /dev/null +++ b/tty/hsu-some-code-cleanup.patch @@ -0,0 +1,282 @@ +From alan@linux.intel.com Mon Jul 26 14:23:31 2010 +From: Alan Cox <alan@linux.intel.com> +Subject: hsu: some code cleanup +To: greg@kroah.com, linux-serial@vger.kernel.org +Date: Mon, 26 Jul 2010 10:18:32 +0100 +Message-ID: <20100726091828.21579.78601.stgit@localhost.localdomain> + +From: Feng Tang <feng.tang@intel.com> + +Major changes are: +* refine the comments in the driver +* remove unused member from structure "hsu_port" +* extended spin_lock protoction for dma mode in port_irq() + +Signed-off-by: Feng Tang <feng.tang@intel.com> +Signed-off-by: Alan Cox <alan@linux.intel.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/mfd.c | 85 +++++++++++---------------------------------------- + 1 file changed, 19 insertions(+), 66 deletions(-) + +--- a/drivers/serial/mfd.c ++++ b/drivers/serial/mfd.c +@@ -3,7 +3,7 @@ + * + * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ + * +- * (C) Copyright 2009 Intel Corporation ++ * (C) Copyright 2010 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License +@@ -11,30 +11,16 @@ + * of the License. + */ + +- + /* Notes: +- * 1. there should be 2 types of register access method, one for +- * UART ports, the other for the general purpose registers +- * +- * 2. It used to have a Irda port, but was defeatured recently +- * +- * 3. Based on the info from HSU MAS, 0/1 channel are assigned to +- * port0, 2/3 chan to port 1, 4/5 chan to port 3. Even number +- * chan will be read, odd chan for write +- * +- * 4. HUS supports both the 64B and 16B FIFO version, but this driver +- * will only use 64B version ++ * 1. DMA channel allocation: 0/1 channel are assigned to port 0, ++ * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans ++ * are used for RX, odd chans for TX + * +- * 5. In A0 stepping, UART will not support TX half empty flag, thus +- * need add a #ifdef judgement ++ * 2. In A0 stepping, UART will not support TX half empty flag + * +- * 6. One more bug for A0, the loopback mode won't support AFC +- * auto-flow control +- * +- * 7. HSU has some special FCR control bits, we add it to serial_reg.h +- * +- * 8. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always asserted, +- * only when the HW is reset the DDCD and DDSR will be triggered ++ * 3. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always ++ * asserted, only when the HW is reset the DDCD and DDSR will ++ * be triggered + */ + + #include <linux/module.h> +@@ -75,7 +61,7 @@ struct hsu_dma_buffer { + + struct hsu_dma_chan { + u32 id; +- u32 dirt; /* to or from device */ ++ enum dma_data_direction dirt; + struct uart_hsu_port *uport; + void __iomem *reg; + struct timer_list rx_timer; /* only needed by RX channel */ +@@ -102,8 +88,6 @@ struct uart_hsu_port { + + /* Top level data structure of HSU */ + struct hsu_port { +- struct pci_device *pdev; +- + void __iomem *reg; + unsigned long paddr; + unsigned long iolen; +@@ -112,23 +96,9 @@ struct hsu_port { + struct uart_hsu_port port[3]; + struct hsu_dma_chan chans[10]; + +-#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; +-#endif + }; + +-static inline void hexdump(char *str, u8 *addr, int cnt) +-{ +- int i; +- +- for (i = 0; i < cnt; i += 8) { +- printk("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", +- addr[i], addr[i+1], addr[i+2], addr[i+3], +- addr[i+4], addr[i+5], addr[i+6], addr[i+7]); +- printk("\n"); +- } +-} +- + static inline unsigned int serial_in(struct uart_hsu_port *up, int offset) + { + unsigned int val; +@@ -353,9 +323,6 @@ void hsu_dma_tx(struct uart_hsu_port *up + | (0x1 << 8) + | (0x1 << 16) + | (0x1 << 24)); +- +- WARN(chan_readl(up->txc, HSU_CH_CR) & 0x1, +- "TX channel has already be started!!\n"); + up->dma_tx_on = 1; + chan_writel(up->txc, HSU_CH_CR, 0x1); + } +@@ -367,7 +334,6 @@ void hsu_dma_tx(struct uart_hsu_port *up + /* The buffer is already cache coherent */ + void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) + { +- /* Need start RX dma channel here */ + dbuf->ofs = 0; + + chan_writel(rxc, HSU_CH_BSR, 32); +@@ -426,35 +392,32 @@ void hsu_dma_rx(struct uart_hsu_port *up + return; + + /* +- * first need to know how many is already transferred, ++ * First need to know how many is already transferred, + * then check if its a timeout DMA irq, and return + * the trail bytes out, push them up and reenable the +- * channel, better to use 2 descriptors at the same time ++ * channel + */ + +- /* timeout IRQ, need wait some time, see Errata 2 */ ++ /* Timeout IRQ, need wait some time, see Errata 2 */ + if (int_sts & 0xf00) + udelay(2); + + /* Stop the channel */ + chan_writel(chan, HSU_CH_CR, 0x0); + +- /* We can use 2 ways to calc the actual transfer len */ + count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; +- + if (!count) { +- /* restart the channel before we leave */ ++ /* Restart the channel before we leave */ + chan_writel(chan, HSU_CH_CR, 0x3); + return; + } +- + del_timer(&chan->rx_timer); + + dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, + dbuf->dma_size, DMA_FROM_DEVICE); + + /* +- * head will only wrap around when we recycle ++ * Head will only wrap around when we recycle + * the DMA buffer, and when that happens, we + * explicitly set tail to 0. So head will + * always be greater than tail. +@@ -496,10 +459,6 @@ static void serial_hsu_stop_rx(struct ua + } + } + +-/* +- * if there is error flag, should we just reset the FIFO or keeps +- * working on it +- */ + static inline void receive_chars(struct uart_hsu_port *up, int *status) + { + struct tty_struct *tty = up->port.state->port.tty; +@@ -571,7 +530,6 @@ static void transmit_chars(struct uart_h + { + struct circ_buf *xmit = &up->port.state->xmit; + int count; +- int i = 0; /* for debug use */ + + if (up->port.x_char) { + serial_out(up, UART_TX, up->port.x_char); +@@ -592,13 +550,11 @@ static void transmit_chars(struct uart_h + * into it won't clear the EMPT bit, so we may need be cautious + * by useing a shorter buffer + */ +- /* count = up->port.fifosize; */ + count = up->port.fifosize - 4; + #endif + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); +- i++; + + up->port.icount.tx++; + if (uart_circ_empty(xmit)) +@@ -628,7 +584,7 @@ static inline void check_modem_status(st + /* We may only get DDCD when HW init and reset */ + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); +- /* will start/stop_tx accordingly */ ++ /* Will start/stop_tx accordingly */ + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + +@@ -647,6 +603,7 @@ static irqreturn_t port_irq(int irq, voi + if (unlikely(!up->running)) + return IRQ_NONE; + ++ spin_lock_irqsave(&up->port.lock, flags); + if (up->use_dma) { + lsr = serial_in(up, UART_LSR); + if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | +@@ -655,10 +612,10 @@ static irqreturn_t port_irq(int irq, voi + "Got lsr irq while using DMA, lsr = 0x%2x\n", + lsr); + check_modem_status(up); ++ spin_unlock_irqrestore(&up->port.lock, flags); + return IRQ_HANDLED; + } + +- spin_lock_irqsave(&up->port.lock, flags); + iir = serial_in(up, UART_IIR); + if (iir & UART_IIR_NO_INT) { + spin_unlock_irqrestore(&up->port.lock, flags); +@@ -666,9 +623,9 @@ static irqreturn_t port_irq(int irq, voi + } + + lsr = serial_in(up, UART_LSR); +- + if (lsr & UART_LSR_DR) + receive_chars(up, &lsr); ++ check_modem_status(up); + + /* lsr will be renewed during the receive_chars */ + if (lsr & UART_LSR_THRE) +@@ -701,7 +658,6 @@ static inline void dma_chan_irq(struct h + + /* Tx channel */ + if (chan->dirt == DMA_TO_DEVICE) { +- /* dma for irq should be done */ + chan_writel(chan, HSU_CH_CR, 0x0); + up->dma_tx_on = 0; + hsu_dma_tx(up); +@@ -851,7 +807,6 @@ static int serial_hsu_startup(struct uar + spin_unlock_irqrestore(&up->port.lock, flags); + + /* DMA init */ +- /* When use DMA, TX/RX's FIFO and IRQ should be disabled */ + if (up->use_dma) { + struct hsu_dma_buffer *dbuf; + struct circ_buf *xmit = &port->state->xmit; +@@ -1090,11 +1045,9 @@ static int serial_hsu_request_port(struc + + static void serial_hsu_config_port(struct uart_port *port, int flags) + { +-#if 0 + struct uart_hsu_port *up = + container_of(port, struct uart_hsu_port, port); + up->port.type = PORT_MFD; +-#endif + } + + static int +@@ -1426,7 +1379,7 @@ static void hsu_global_init(void) + uport->port.ops = &serial_hsu_pops; + uport->port.line = i; + uport->port.flags = UPF_IOREMAP; +- /* make the maxim support rate to 2746800 bps */ ++ /* set the scalable maxim support rate to 2746800 bps */ + uport->port.uartclk = 115200 * 24 * 16; + + uport->running = 0; diff --git a/tty/mxser-remove-unnesesary-null-check.patch b/tty/mxser-remove-unnesesary-null-check.patch new file mode 100644 index 00000000000000..ac753788456305 --- /dev/null +++ b/tty/mxser-remove-unnesesary-null-check.patch @@ -0,0 +1,33 @@ +From segooon@gmail.com Mon Jul 26 14:24:13 2010 +From: Kulikov Vasiliy <segooon@gmail.com> +To: kernel-janitors@vger.kernel.org +Cc: Jiri Slaby <jirislaby@gmail.com>, + Greg Kroah-Hartman <gregkh@suse.de>, Alan Cox <alan@linux.intel.com>, + Andrew Morton <akpm@linux-foundation.org>, Tejun Heo <tj@kernel.org>, + linux-kernel@vger.kernel.org +Subject: mxser: remove unnesesary NULL check +Date: Fri, 23 Jul 2010 20:34:53 +0400 +Message-Id: <1279902893-27006-1-git-send-email-segooon@gmail.com> + +mxser_transmit_chars(tty, port) is called only from mxser_interrupt(). +NULL check is performed in mxser_interrupt() so it is redundant here. + +Signed-off-by: Kulikov Vasiliy <segooon@gmail.com> +Acked-by: Jiri Slaby <jirislaby@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/char/mxser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/char/mxser.c ++++ b/drivers/char/mxser.c +@@ -2193,7 +2193,7 @@ static void mxser_transmit_chars(struct + port->mon_data.up_txcnt += (cnt - port->xmit_cnt); + port->icount.tx += (cnt - port->xmit_cnt); + +- if (port->xmit_cnt < WAKEUP_CHARS && tty) ++ if (port->xmit_cnt < WAKEUP_CHARS) + tty_wakeup(tty); + + if (port->xmit_cnt <= 0) { diff --git a/tty/serial-add-support-for-ox16pci958-card.patch b/tty/serial-add-support-for-ox16pci958-card.patch new file mode 100644 index 00000000000000..490a2e1fc0f9c5 --- /dev/null +++ b/tty/serial-add-support-for-ox16pci958-card.patch @@ -0,0 +1,65 @@ +From a.beregalov@gmail.com Mon Jul 26 14:21:38 2010 +From: Alexander Beregalov <a.beregalov@gmail.com> +To: gregkh@suse.de +Cc: linux-kernel@vger.kernel.org, + Lytochkin Boris <lytboris@gmail.com>, + Alexander Beregalov <a.beregalov@gmail.com> +Subject: [PATCH] serial: add support for OX16PCI958 card +Date: Mon, 26 Jul 2010 10:02:26 +0400 +Message-Id: <1280124146-24735-1-git-send-email-a.beregalov@gmail.com> + +From: Lytochkin Boris <lytboris@gmail.com> + +Signed-off-by: Lytochkin Boris <lytboris@gmail.com> +Tested-by: Lytochkin Boris <lytboris@gmail.com> +Signed-off-by: Alexander Beregalov <a.beregalov@gmail.com> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/serial/8250_pci.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/serial/8250_pci.c ++++ b/drivers/serial/8250_pci.c +@@ -994,6 +994,7 @@ static int skip_tx_en_setup(struct seria + #define PCI_DEVICE_ID_TITAN_800E 0xA014 + #define PCI_DEVICE_ID_TITAN_200EI 0xA016 + #define PCI_DEVICE_ID_TITAN_200EISI 0xA017 ++#define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 + + /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ + #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 +@@ -1542,6 +1543,8 @@ enum pci_board_num_t { + pbn_b2_4_921600, + pbn_b2_8_921600, + ++ pbn_b2_8_1152000, ++ + pbn_b2_bt_1_115200, + pbn_b2_bt_2_115200, + pbn_b2_bt_4_115200, +@@ -1960,6 +1963,13 @@ static struct pciserial_board pci_boards + .uart_offset = 8, + }, + ++ [pbn_b2_8_1152000] = { ++ .flags = FL_BASE2, ++ .num_ports = 8, ++ .base_baud = 1152000, ++ .uart_offset = 8, ++ }, ++ + [pbn_b2_bt_1_115200] = { + .flags = FL_BASE2|FL_BASE_BARS, + .num_ports = 1, +@@ -2875,6 +2885,9 @@ static struct pci_device_id serial_pci_t + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_921600 }, ++ { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI958, ++ PCI_ANY_ID , PCI_ANY_ID, 0, 0, ++ pbn_b2_8_1152000 }, + + /* + * Oxford Semiconductor Inc. Tornado PCI express device range. diff --git a/usb/usb-gadget-file_storage-serial-parameter-even-if-not-test-mode.patch b/usb/usb-gadget-file_storage-serial-parameter-even-if-not-test-mode.patch new file mode 100644 index 00000000000000..b28f922b984297 --- /dev/null +++ b/usb/usb-gadget-file_storage-serial-parameter-even-if-not-test-mode.patch @@ -0,0 +1,104 @@ +From m.nazarewicz@samsung.com Mon Jul 26 14:26:35 2010 +Date: Thu, 22 Jul 2010 14:16:37 +0200 +From: Michal Nazarewicz <m.nazarewicz@samsung.com> +Subject: USB: gadget: file_storage: serial parameter even if not test mode +To: linux-usb@vger.kernel.org +Cc: Kyungmin Park <kyungmin.park@samsung.com>, + Marek Szyprowski <m.szyprowski@samsung.com>, + David Brownell <david-b@pacbell.net>, Alan Stern <stern@rowland.harvard.edu>, + Greg KH <greg@kroah.com>, linux-kernel@vger.kernel.org, + Yann Cantin <yann.cantin@laposte.net> +Message-id: <709d887b2249e9651060729eb62b29a1d3edc256.1279794290.git.m.nazarewicz@samsung.com> + +Moved the serial parameter handling code out of "#ifdef +CONFIG_USB_FILE_STORAGE_TEST". + +This modifies Yann Cantin's commit "USB: Add a serial number +parameter to g_file_storage" module as per Alan Stern's request. + +Signed-off-by: Michal Nazarewicz <m.nazarewicz@samsung.com> +Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> +Acked-by: Alan Stern <stern@rowland.harvard.edu> +Tested-by: Anand Gadiyar <gadiyar@ti.com> +Cc: David Brownell <david-b@pacbell.net> +Cc: Yann Cantin <yann.cantin@laposte.net> + +--- + drivers/usb/gadget/file_storage.c | 20 +++++++++++--------- + 1 file changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/usb/gadget/file_storage.c ++++ b/drivers/usb/gadget/file_storage.c +@@ -321,7 +321,7 @@ static struct { + unsigned short vendor; + unsigned short product; + unsigned short release; +- char *serial_parm; ++ char *serial; + unsigned int buflen; + + int transport_type; +@@ -365,6 +365,8 @@ MODULE_PARM_DESC(stall, "false to preven + module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); + MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); + ++module_param_named(serial, mod_data.serial, charp, S_IRUGO); ++MODULE_PARM_DESC(serial, "USB serial number"); + + /* In the non-TEST version, only the module parameters listed above + * are available. */ +@@ -386,9 +388,6 @@ MODULE_PARM_DESC(product, "USB Product I + module_param_named(release, mod_data.release, ushort, S_IRUGO); + MODULE_PARM_DESC(release, "USB release number"); + +-module_param_named(serial, mod_data.serial_parm, charp, S_IRUGO); +-MODULE_PARM_DESC(serial, "USB serial number"); +- + module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); + MODULE_PARM_DESC(buflen, "I/O buffer size"); + +@@ -3291,10 +3290,12 @@ static int __init check_parameters(struc + return -ETOOSMALL; + } + ++#endif /* CONFIG_USB_FILE_STORAGE_TEST */ ++ + /* Serial string handling. + * On a real device, the serial string would be loaded + * from permanent storage. */ +- if (mod_data.serial_parm) { ++ if (mod_data.serial) { + const char *ch; + unsigned len = 0; + +@@ -3303,7 +3304,7 @@ static int __init check_parameters(struc + * 12 uppercase hexadecimal characters. + * BBB need at least 12 uppercase hexadecimal characters, + * with a maximum of 126. */ +- for (ch = mod_data.serial_parm; *ch; ++ch) { ++ for (ch = mod_data.serial; *ch; ++ch) { + ++len; + if ((*ch < '0' || *ch > '9') && + (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ +@@ -3322,8 +3323,11 @@ static int __init check_parameters(struc + "Failing back to default\n"); + goto fill_serial; + } +- fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial_parm; ++ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; + } else { ++ WARNING(fsg, ++ "Userspace failed to provide serial number; " ++ "Failing back to default\n"); + fill_serial: + /* Serial number not specified or invalid, make our own. + * We just encode it from the driver version string, +@@ -3339,8 +3343,6 @@ fill_serial: + } + } + +-#endif /* CONFIG_USB_FILE_STORAGE_TEST */ +- + return 0; + } + diff --git a/usb/usb-imx21-hcd-set-task-state-with-schedule_timeout_uninterruptible.patch b/usb/usb-imx21-hcd-set-task-state-with-schedule_timeout_uninterruptible.patch new file mode 100644 index 00000000000000..3ad0b83b5c8f25 --- /dev/null +++ b/usb/usb-imx21-hcd-set-task-state-with-schedule_timeout_uninterruptible.patch @@ -0,0 +1,32 @@ +From linux-usb-owner@vger.kernel.org Mon Jul 26 14:22:01 2010 +From: Kulikov Vasiliy <segooon@gmail.com> +To: kernel-janitors@vger.kernel.org +Cc: Greg Kroah-Hartman <gregkh@suse.de>, Tejun Heo <tj@kernel.org>, + Martin Fuzzey <mfuzzey@gmail.com>, linux-usb@vger.kernel.org, + linux-kernel@vger.kernel.org +Subject: [PATCH] usb: imx21-hcd: set task state with schedule_timeout_uninterruptible() +Date: Mon, 26 Jul 2010 12:26:22 +0400 +Message-Id: <1280132783-8182-1-git-send-email-segooon@gmail.com> + +imx21_hc_reset() uses schedule_timeout() without setting state to +STATE_(UN)INTERRUPTIBLE. As it is called in cycle without checking of +pending signals, use schedule_timeout_uninterruptible(). + +Signed-off-by: Kulikov Vasiliy <segooon@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/imx21-hcd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/host/imx21-hcd.c ++++ b/drivers/usb/host/imx21-hcd.c +@@ -1521,7 +1521,7 @@ static int imx21_hc_reset(struct usb_hcd + return -ETIMEDOUT; + } + spin_unlock_irq(&imx21->lock); +- schedule_timeout(1); ++ schedule_timeout_uninterruptible(1); + spin_lock_irq(&imx21->lock); + } + spin_unlock_irqrestore(&imx21->lock, flags); diff --git a/usb/usb-serial-enabling-support-for-segway-rmp-in-ftdi_sio.patch b/usb/usb-serial-enabling-support-for-segway-rmp-in-ftdi_sio.patch new file mode 100644 index 00000000000000..727e7155ecca04 --- /dev/null +++ b/usb/usb-serial-enabling-support-for-segway-rmp-in-ftdi_sio.patch @@ -0,0 +1,49 @@ +From jgrogers@gatech.edu Mon Jul 26 14:18:48 2010 +From: John Rogers <jgrogers@gatech.edu> +Subject: USB: serial: enabling support for Segway RMP in ftdi_sio +Date: Sat, 24 Jul 2010 09:50:52 -0400 +Message-Id: <9CA0AFB3-3DF4-496D-8ECC-1C60C90C861B@mail.gatech.edu> +Cc: linux-usb@vger.kernel.org +To: greg@kroah.com + +From: John G. Rogers <jgrogers@gmail.com> + +I have added the ProductID=0xe729 VendorID=FTDI_VID=0x0403 which will +enable support for the Segway Robotic Mobility Platform (RMP200) in the +ftdi_sio kernel module. Currently, users of the Segway RMP200 must use +a RUN+="/sbin/modprobe -q ftdi-sio product=0xe729 vendor=0x0403 in a +udev rule to get the ftdi_sio module to handle the usb interface and +mount it on /dev/ttyXXX. This is not a good solution because some users +will have multiple USB to Serial converters which will use the ftdi_sio +module. + +Signed-off-by: John Rogers <jgrogers@gmail.com> +Cc: stable <stable@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/ftdi_sio.c | 1 + + drivers/usb/serial/ftdi_sio_ids.h | 5 +++++ + 2 files changed, 6 insertions(+) + +--- a/drivers/usb/serial/ftdi_sio.c ++++ b/drivers/usb/serial/ftdi_sio.c +@@ -746,6 +746,7 @@ static struct usb_device_id id_table_com + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, ++ { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, + { }, /* Optional parameter entry */ + { } /* Terminating entry */ + }; +--- a/drivers/usb/serial/ftdi_sio_ids.h ++++ b/drivers/usb/serial/ftdi_sio_ids.h +@@ -1032,3 +1032,8 @@ + #define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 + #define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 + ++/* ++ * Segway Robotic Mobility Platform USB interface (using VID 0x0403) ++ * Submitted by John G. Rogers ++ */ ++#define SEGWAY_RMP200_PID 0xe729 diff --git a/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch b/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch deleted file mode 100644 index 59c6f4834cb351..00000000000000 --- a/usb/usb-uvc-move-constants-and-structures-definitions-to-linux-usb-video.h.patch +++ /dev/null @@ -1,1044 +0,0 @@ -From laurent.pinchart@ideasonboard.com Wed Jun 16 13:25:39 2010 -From: Laurent Pinchart <laurent.pinchart@ideasonboard.com> -Date: Mon, 7 Jun 2010 13:09:47 +0200 -Subject: USB: uvc: Move constants and structures definitions to linux/usb/video.h -To: linux-usb@vger.kernel.org -Message-ID: <1275908987-5774-1-git-send-email-laurent.pinchart@ideasonboard.com> - - -The UVC host and gadget drivers both define constants and structures in -private header files. Move all those definitions to linux/usb/video.h -where they can be shared by the two drivers (and be available for -userspace applications). - -Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> - ---- - drivers/media/video/uvc/uvcvideo.h | 19 - - drivers/usb/gadget/f_uvc.c | 16 - - drivers/usb/gadget/f_uvc.h | 352 -------------------------------- - drivers/usb/gadget/uvc.h | 36 --- - drivers/usb/gadget/webcam.c | 24 +- - include/linux/usb/video.h | 397 +++++++++++++++++++++++++++++++++++++ - 6 files changed, 418 insertions(+), 426 deletions(-) - ---- a/drivers/media/video/uvc/uvcvideo.h -+++ b/drivers/media/video/uvc/uvcvideo.h -@@ -179,25 +179,6 @@ struct uvc_device; - /* TODO: Put the most frequently accessed fields at the beginning of - * structures to maximize cache efficiency. - */ --struct uvc_streaming_control { -- __u16 bmHint; -- __u8 bFormatIndex; -- __u8 bFrameIndex; -- __u32 dwFrameInterval; -- __u16 wKeyFrameRate; -- __u16 wPFrameRate; -- __u16 wCompQuality; -- __u16 wCompWindowSize; -- __u16 wDelay; -- __u32 dwMaxVideoFrameSize; -- __u32 dwMaxPayloadTransferSize; -- __u32 dwClockFrequency; -- __u8 bmFramingInfo; -- __u8 bPreferedVersion; -- __u8 bMinVersion; -- __u8 bMaxVersion; --}; -- - struct uvc_menu_info { - __u32 value; - __u8 name[32]; ---- a/drivers/usb/gadget/f_uvc.c -+++ b/drivers/usb/gadget/f_uvc.c -@@ -61,12 +61,12 @@ static struct usb_gadget_strings *uvc_fu - #define UVC_INTF_VIDEO_STREAMING 1 - - static struct usb_interface_assoc_descriptor uvc_iad __initdata = { -- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, -+ .bLength = sizeof(uvc_iad), - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - .bFirstInterface = 0, - .bInterfaceCount = 2, - .bFunctionClass = USB_CLASS_VIDEO, -- .bFunctionSubClass = 0x03, -+ .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, - .bFunctionProtocol = 0x00, - .iFunction = 0, - }; -@@ -78,7 +78,7 @@ static struct usb_interface_descriptor u - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_VIDEO, -- .bInterfaceSubClass = 0x01, -+ .bInterfaceSubClass = UVC_SC_VIDEOCONTROL, - .bInterfaceProtocol = 0x00, - .iInterface = 0, - }; -@@ -106,7 +106,7 @@ static struct usb_interface_descriptor u - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_VIDEO, -- .bInterfaceSubClass = 0x02, -+ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, - .bInterfaceProtocol = 0x00, - .iInterface = 0, - }; -@@ -118,7 +118,7 @@ static struct usb_interface_descriptor u - .bAlternateSetting = 1, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_VIDEO, -- .bInterfaceSubClass = 0x02, -+ .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, - .bInterfaceProtocol = 0x00, - .iInterface = 0, - }; -@@ -603,15 +603,15 @@ uvc_bind_config(struct usb_configuration - - /* Validate the descriptors. */ - if (control == NULL || control[0] == NULL || -- control[0]->bDescriptorSubType != UVC_DT_HEADER) -+ control[0]->bDescriptorSubType != UVC_VC_HEADER) - goto error; - - if (fs_streaming == NULL || fs_streaming[0] == NULL || -- fs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) -+ fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) - goto error; - - if (hs_streaming == NULL || hs_streaming[0] == NULL || -- hs_streaming[0]->bDescriptorSubType != UVC_DT_INPUT_HEADER) -+ hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) - goto error; - - uvc->desc.control = control; ---- a/drivers/usb/gadget/f_uvc.h -+++ b/drivers/usb/gadget/f_uvc.h -@@ -15,357 +15,7 @@ - #define _F_UVC_H_ - - #include <linux/usb/composite.h> -- --#define USB_CLASS_VIDEO_CONTROL 1 --#define USB_CLASS_VIDEO_STREAMING 2 -- --struct uvc_descriptor_header { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; --} __attribute__ ((packed)); -- --struct uvc_header_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u16 bcdUVC; -- __u16 wTotalLength; -- __u32 dwClockFrequency; -- __u8 bInCollection; -- __u8 baInterfaceNr[]; --} __attribute__((__packed__)); -- --#define UVC_HEADER_DESCRIPTOR(n) uvc_header_descriptor_##n -- --#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ --struct UVC_HEADER_DESCRIPTOR(n) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u16 bcdUVC; \ -- __u16 wTotalLength; \ -- __u32 dwClockFrequency; \ -- __u8 bInCollection; \ -- __u8 baInterfaceNr[n]; \ --} __attribute__ ((packed)) -- --struct uvc_input_terminal_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bTerminalID; -- __u16 wTerminalType; -- __u8 bAssocTerminal; -- __u8 iTerminal; --} __attribute__((__packed__)); -- --struct uvc_output_terminal_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bTerminalID; -- __u16 wTerminalType; -- __u8 bAssocTerminal; -- __u8 bSourceID; -- __u8 iTerminal; --} __attribute__((__packed__)); -- --struct uvc_camera_terminal_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bTerminalID; -- __u16 wTerminalType; -- __u8 bAssocTerminal; -- __u8 iTerminal; -- __u16 wObjectiveFocalLengthMin; -- __u16 wObjectiveFocalLengthMax; -- __u16 wOcularFocalLength; -- __u8 bControlSize; -- __u8 bmControls[3]; --} __attribute__((__packed__)); -- --struct uvc_selector_unit_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bUnitID; -- __u8 bNrInPins; -- __u8 baSourceID[0]; -- __u8 iSelector; --} __attribute__((__packed__)); -- --#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ -- uvc_selector_unit_descriptor_##n -- --#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ --struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bUnitID; \ -- __u8 bNrInPins; \ -- __u8 baSourceID[n]; \ -- __u8 iSelector; \ --} __attribute__ ((packed)) -- --struct uvc_processing_unit_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bUnitID; -- __u8 bSourceID; -- __u16 wMaxMultiplier; -- __u8 bControlSize; -- __u8 bmControls[2]; -- __u8 iProcessing; --} __attribute__((__packed__)); -- --struct uvc_extension_unit_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bUnitID; -- __u8 guidExtensionCode[16]; -- __u8 bNumControls; -- __u8 bNrInPins; -- __u8 baSourceID[0]; -- __u8 bControlSize; -- __u8 bmControls[0]; -- __u8 iExtension; --} __attribute__((__packed__)); -- --#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ -- uvc_extension_unit_descriptor_##p_##n -- --#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ --struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bUnitID; \ -- __u8 guidExtensionCode[16]; \ -- __u8 bNumControls; \ -- __u8 bNrInPins; \ -- __u8 baSourceID[p]; \ -- __u8 bControlSize; \ -- __u8 bmControls[n]; \ -- __u8 iExtension; \ --} __attribute__ ((packed)) -- --struct uvc_control_endpoint_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u16 wMaxTransferSize; --} __attribute__((__packed__)); -- --#define UVC_DT_HEADER 1 --#define UVC_DT_INPUT_TERMINAL 2 --#define UVC_DT_OUTPUT_TERMINAL 3 --#define UVC_DT_SELECTOR_UNIT 4 --#define UVC_DT_PROCESSING_UNIT 5 --#define UVC_DT_EXTENSION_UNIT 6 -- --#define UVC_DT_HEADER_SIZE(n) (12+(n)) --#define UVC_DT_INPUT_TERMINAL_SIZE 8 --#define UVC_DT_OUTPUT_TERMINAL_SIZE 9 --#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) --#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n)) --#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) --#define UVC_DT_EXTENSION_UNIT_SIZE(p,n) (24+(p)+(n)) --#define UVC_DT_CONTROL_ENDPOINT_SIZE 5 -- --struct uvc_input_header_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bNumFormats; -- __u16 wTotalLength; -- __u8 bEndpointAddress; -- __u8 bmInfo; -- __u8 bTerminalLink; -- __u8 bStillCaptureMethod; -- __u8 bTriggerSupport; -- __u8 bTriggerUsage; -- __u8 bControlSize; -- __u8 bmaControls[]; --} __attribute__((__packed__)); -- --#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ -- uvc_input_header_descriptor_##n_##p -- --#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ --struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bNumFormats; \ -- __u16 wTotalLength; \ -- __u8 bEndpointAddress; \ -- __u8 bmInfo; \ -- __u8 bTerminalLink; \ -- __u8 bStillCaptureMethod; \ -- __u8 bTriggerSupport; \ -- __u8 bTriggerUsage; \ -- __u8 bControlSize; \ -- __u8 bmaControls[p][n]; \ --} __attribute__ ((packed)) -- --struct uvc_output_header_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bNumFormats; -- __u16 wTotalLength; -- __u8 bEndpointAddress; -- __u8 bTerminalLink; -- __u8 bControlSize; -- __u8 bmaControls[]; --} __attribute__((__packed__)); -- --#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ -- uvc_output_header_descriptor_##n_##p -- --#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ --struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bNumFormats; \ -- __u16 wTotalLength; \ -- __u8 bEndpointAddress; \ -- __u8 bTerminalLink; \ -- __u8 bControlSize; \ -- __u8 bmaControls[p][n]; \ --} __attribute__ ((packed)) -- --struct uvc_format_uncompressed { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bFormatIndex; -- __u8 bNumFrameDescriptors; -- __u8 guidFormat[16]; -- __u8 bBitsPerPixel; -- __u8 bDefaultFrameIndex; -- __u8 bAspectRatioX; -- __u8 bAspectRatioY; -- __u8 bmInterfaceFlags; -- __u8 bCopyProtect; --} __attribute__((__packed__)); -- --struct uvc_frame_uncompressed { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bFrameIndex; -- __u8 bmCapabilities; -- __u16 wWidth; -- __u16 wHeight; -- __u32 dwMinBitRate; -- __u32 dwMaxBitRate; -- __u32 dwMaxVideoFrameBufferSize; -- __u32 dwDefaultFrameInterval; -- __u8 bFrameIntervalType; -- __u32 dwFrameInterval[]; --} __attribute__((__packed__)); -- --#define UVC_FRAME_UNCOMPRESSED(n) \ -- uvc_frame_uncompressed_##n -- --#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ --struct UVC_FRAME_UNCOMPRESSED(n) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bFrameIndex; \ -- __u8 bmCapabilities; \ -- __u16 wWidth; \ -- __u16 wHeight; \ -- __u32 dwMinBitRate; \ -- __u32 dwMaxBitRate; \ -- __u32 dwMaxVideoFrameBufferSize; \ -- __u32 dwDefaultFrameInterval; \ -- __u8 bFrameIntervalType; \ -- __u32 dwFrameInterval[n]; \ --} __attribute__ ((packed)) -- --struct uvc_format_mjpeg { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bFormatIndex; -- __u8 bNumFrameDescriptors; -- __u8 bmFlags; -- __u8 bDefaultFrameIndex; -- __u8 bAspectRatioX; -- __u8 bAspectRatioY; -- __u8 bmInterfaceFlags; -- __u8 bCopyProtect; --} __attribute__((__packed__)); -- --struct uvc_frame_mjpeg { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bFrameIndex; -- __u8 bmCapabilities; -- __u16 wWidth; -- __u16 wHeight; -- __u32 dwMinBitRate; -- __u32 dwMaxBitRate; -- __u32 dwMaxVideoFrameBufferSize; -- __u32 dwDefaultFrameInterval; -- __u8 bFrameIntervalType; -- __u32 dwFrameInterval[]; --} __attribute__((__packed__)); -- --#define UVC_FRAME_MJPEG(n) \ -- uvc_frame_mjpeg_##n -- --#define DECLARE_UVC_FRAME_MJPEG(n) \ --struct UVC_FRAME_MJPEG(n) { \ -- __u8 bLength; \ -- __u8 bDescriptorType; \ -- __u8 bDescriptorSubType; \ -- __u8 bFrameIndex; \ -- __u8 bmCapabilities; \ -- __u16 wWidth; \ -- __u16 wHeight; \ -- __u32 dwMinBitRate; \ -- __u32 dwMaxBitRate; \ -- __u32 dwMaxVideoFrameBufferSize; \ -- __u32 dwDefaultFrameInterval; \ -- __u8 bFrameIntervalType; \ -- __u32 dwFrameInterval[n]; \ --} __attribute__ ((packed)) -- --struct uvc_color_matching_descriptor { -- __u8 bLength; -- __u8 bDescriptorType; -- __u8 bDescriptorSubType; -- __u8 bColorPrimaries; -- __u8 bTransferCharacteristics; -- __u8 bMatrixCoefficients; --} __attribute__((__packed__)); -- --#define UVC_DT_INPUT_HEADER 1 --#define UVC_DT_OUTPUT_HEADER 2 --#define UVC_DT_FORMAT_UNCOMPRESSED 4 --#define UVC_DT_FRAME_UNCOMPRESSED 5 --#define UVC_DT_FORMAT_MJPEG 6 --#define UVC_DT_FRAME_MJPEG 7 --#define UVC_DT_COLOR_MATCHING 13 -- --#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) --#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) --#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27 --#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) --#define UVC_DT_FORMAT_MJPEG_SIZE 11 --#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) --#define UVC_DT_COLOR_MATCHING_SIZE 6 -+#include <linux/usb/video.h> - - extern int uvc_bind_config(struct usb_configuration *c, - const struct uvc_descriptor_header * const *control, ---- a/drivers/usb/gadget/uvc.h -+++ b/drivers/usb/gadget/uvc.h -@@ -48,39 +48,6 @@ struct uvc_event - #define UVC_INTF_STREAMING 1 - - /* ------------------------------------------------------------------------ -- * UVC constants & structures -- */ -- --/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ --#define UVC_STREAM_EOH (1 << 7) --#define UVC_STREAM_ERR (1 << 6) --#define UVC_STREAM_STI (1 << 5) --#define UVC_STREAM_RES (1 << 4) --#define UVC_STREAM_SCR (1 << 3) --#define UVC_STREAM_PTS (1 << 2) --#define UVC_STREAM_EOF (1 << 1) --#define UVC_STREAM_FID (1 << 0) -- --struct uvc_streaming_control { -- __u16 bmHint; -- __u8 bFormatIndex; -- __u8 bFrameIndex; -- __u32 dwFrameInterval; -- __u16 wKeyFrameRate; -- __u16 wPFrameRate; -- __u16 wCompQuality; -- __u16 wCompWindowSize; -- __u16 wDelay; -- __u32 dwMaxVideoFrameSize; -- __u32 dwMaxPayloadTransferSize; -- __u32 dwClockFrequency; -- __u8 bmFramingInfo; -- __u8 bPreferedVersion; -- __u8 bMinVersion; -- __u8 bMaxVersion; --} __attribute__((__packed__)); -- --/* ------------------------------------------------------------------------ - * Debugging, printing and logging - */ - -@@ -137,9 +104,6 @@ extern unsigned int uvc_trace_param; - #define UVC_MAX_REQUEST_SIZE 64 - #define UVC_MAX_EVENTS 4 - --#define USB_DT_INTERFACE_ASSOCIATION_SIZE 8 --#define USB_CLASS_MISC 0xef -- - /* ------------------------------------------------------------------------ - * Structures - */ ---- a/drivers/usb/gadget/webcam.c -+++ b/drivers/usb/gadget/webcam.c -@@ -90,7 +90,7 @@ DECLARE_UVC_HEADER_DESCRIPTOR(1); - static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { - .bLength = UVC_DT_HEADER_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_HEADER, -+ .bDescriptorSubType = UVC_VC_HEADER, - .bcdUVC = cpu_to_le16(0x0100), - .wTotalLength = 0, /* dynamic */ - .dwClockFrequency = cpu_to_le32(48000000), -@@ -101,7 +101,7 @@ static const struct UVC_HEADER_DESCRIPTO - static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = { - .bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_INPUT_TERMINAL, -+ .bDescriptorSubType = UVC_VC_INPUT_TERMINAL, - .bTerminalID = 1, - .wTerminalType = cpu_to_le16(0x0201), - .bAssocTerminal = 0, -@@ -118,7 +118,7 @@ static const struct uvc_camera_terminal_ - static const struct uvc_processing_unit_descriptor uvc_processing = { - .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_PROCESSING_UNIT, -+ .bDescriptorSubType = UVC_VC_PROCESSING_UNIT, - .bUnitID = 2, - .bSourceID = 1, - .wMaxMultiplier = cpu_to_le16(16*1024), -@@ -131,7 +131,7 @@ static const struct uvc_processing_unit_ - static const struct uvc_output_terminal_descriptor uvc_output_terminal = { - .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_OUTPUT_TERMINAL, -+ .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL, - .bTerminalID = 3, - .wTerminalType = cpu_to_le16(0x0101), - .bAssocTerminal = 0, -@@ -144,7 +144,7 @@ DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2 - static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { - .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_INPUT_HEADER, -+ .bDescriptorSubType = UVC_VS_INPUT_HEADER, - .bNumFormats = 2, - .wTotalLength = 0, /* dynamic */ - .bEndpointAddress = 0, /* dynamic */ -@@ -161,7 +161,7 @@ static const struct UVC_INPUT_HEADER_DES - static const struct uvc_format_uncompressed uvc_format_yuv = { - .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FORMAT_UNCOMPRESSED, -+ .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, - .bFormatIndex = 1, - .bNumFrameDescriptors = 2, - .guidFormat = -@@ -181,7 +181,7 @@ DECLARE_UVC_FRAME_UNCOMPRESSED(3); - static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = { - .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED, -+ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, - .bFrameIndex = 1, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), -@@ -199,7 +199,7 @@ static const struct UVC_FRAME_UNCOMPRESS - static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { - .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FRAME_UNCOMPRESSED, -+ .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, - .bFrameIndex = 2, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), -@@ -215,7 +215,7 @@ static const struct UVC_FRAME_UNCOMPRESS - static const struct uvc_format_mjpeg uvc_format_mjpg = { - .bLength = UVC_DT_FORMAT_MJPEG_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FORMAT_MJPEG, -+ .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, - .bFormatIndex = 2, - .bNumFrameDescriptors = 2, - .bmFlags = 0, -@@ -232,7 +232,7 @@ DECLARE_UVC_FRAME_MJPEG(3); - static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = { - .bLength = UVC_DT_FRAME_MJPEG_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FRAME_MJPEG, -+ .bDescriptorSubType = UVC_VS_FRAME_MJPEG, - .bFrameIndex = 1, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), -@@ -250,7 +250,7 @@ static const struct UVC_FRAME_MJPEG(3) u - static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { - .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_FRAME_MJPEG, -+ .bDescriptorSubType = UVC_VS_FRAME_MJPEG, - .bFrameIndex = 2, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), -@@ -266,7 +266,7 @@ static const struct UVC_FRAME_MJPEG(1) u - static const struct uvc_color_matching_descriptor uvc_color_matching = { - .bLength = UVC_DT_COLOR_MATCHING_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, -- .bDescriptorSubType = UVC_DT_COLOR_MATCHING, -+ .bDescriptorSubType = UVC_VS_COLORFORMAT, - .bColorPrimaries = 1, - .bTransferCharacteristics = 1, - .bMatrixCoefficients = 4, ---- a/include/linux/usb/video.h -+++ b/include/linux/usb/video.h -@@ -160,5 +160,402 @@ - #define UVC_STATUS_TYPE_CONTROL 1 - #define UVC_STATUS_TYPE_STREAMING 2 - -+/* 2.4.3.3. Payload Header Information */ -+#define UVC_STREAM_EOH (1 << 7) -+#define UVC_STREAM_ERR (1 << 6) -+#define UVC_STREAM_STI (1 << 5) -+#define UVC_STREAM_RES (1 << 4) -+#define UVC_STREAM_SCR (1 << 3) -+#define UVC_STREAM_PTS (1 << 2) -+#define UVC_STREAM_EOF (1 << 1) -+#define UVC_STREAM_FID (1 << 0) -+ -+/* ------------------------------------------------------------------------ -+ * UVC structures -+ */ -+ -+/* All UVC descriptors have these 3 fields at the beginning */ -+struct uvc_descriptor_header { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+} __attribute__((packed)); -+ -+/* 3.7.2. Video Control Interface Header Descriptor */ -+struct uvc_header_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u16 bcdUVC; -+ __u16 wTotalLength; -+ __u32 dwClockFrequency; -+ __u8 bInCollection; -+ __u8 baInterfaceNr[]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_HEADER_SIZE(n) (12+(n)) -+ -+#define UVC_HEADER_DESCRIPTOR(n) \ -+ uvc_header_descriptor_##n -+ -+#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \ -+struct UVC_HEADER_DESCRIPTOR(n) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u16 bcdUVC; \ -+ __u16 wTotalLength; \ -+ __u32 dwClockFrequency; \ -+ __u8 bInCollection; \ -+ __u8 baInterfaceNr[n]; \ -+} __attribute__ ((packed)) -+ -+/* 3.7.2.1. Input Terminal Descriptor */ -+struct uvc_input_terminal_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bTerminalID; -+ __u16 wTerminalType; -+ __u8 bAssocTerminal; -+ __u8 iTerminal; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_INPUT_TERMINAL_SIZE 8 -+ -+/* 3.7.2.2. Output Terminal Descriptor */ -+struct uvc_output_terminal_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bTerminalID; -+ __u16 wTerminalType; -+ __u8 bAssocTerminal; -+ __u8 bSourceID; -+ __u8 iTerminal; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_OUTPUT_TERMINAL_SIZE 9 -+ -+/* 3.7.2.3. Camera Terminal Descriptor */ -+struct uvc_camera_terminal_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bTerminalID; -+ __u16 wTerminalType; -+ __u8 bAssocTerminal; -+ __u8 iTerminal; -+ __u16 wObjectiveFocalLengthMin; -+ __u16 wObjectiveFocalLengthMax; -+ __u16 wOcularFocalLength; -+ __u8 bControlSize; -+ __u8 bmControls[3]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n)) -+ -+/* 3.7.2.4. Selector Unit Descriptor */ -+struct uvc_selector_unit_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bUnitID; -+ __u8 bNrInPins; -+ __u8 baSourceID[0]; -+ __u8 iSelector; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n)) -+ -+#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ -+ uvc_selector_unit_descriptor_##n -+ -+#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \ -+struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bUnitID; \ -+ __u8 bNrInPins; \ -+ __u8 baSourceID[n]; \ -+ __u8 iSelector; \ -+} __attribute__ ((packed)) -+ -+/* 3.7.2.5. Processing Unit Descriptor */ -+struct uvc_processing_unit_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bUnitID; -+ __u8 bSourceID; -+ __u16 wMaxMultiplier; -+ __u8 bControlSize; -+ __u8 bmControls[2]; -+ __u8 iProcessing; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n)) -+ -+/* 3.7.2.6. Extension Unit Descriptor */ -+struct uvc_extension_unit_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bUnitID; -+ __u8 guidExtensionCode[16]; -+ __u8 bNumControls; -+ __u8 bNrInPins; -+ __u8 baSourceID[0]; -+ __u8 bControlSize; -+ __u8 bmControls[0]; -+ __u8 iExtension; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n)) -+ -+#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ -+ uvc_extension_unit_descriptor_##p_##n -+ -+#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \ -+struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bUnitID; \ -+ __u8 guidExtensionCode[16]; \ -+ __u8 bNumControls; \ -+ __u8 bNrInPins; \ -+ __u8 baSourceID[p]; \ -+ __u8 bControlSize; \ -+ __u8 bmControls[n]; \ -+ __u8 iExtension; \ -+} __attribute__ ((packed)) -+ -+/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */ -+struct uvc_control_endpoint_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u16 wMaxTransferSize; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_CONTROL_ENDPOINT_SIZE 5 -+ -+/* 3.9.2.1. Input Header Descriptor */ -+struct uvc_input_header_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bNumFormats; -+ __u16 wTotalLength; -+ __u8 bEndpointAddress; -+ __u8 bmInfo; -+ __u8 bTerminalLink; -+ __u8 bStillCaptureMethod; -+ __u8 bTriggerSupport; -+ __u8 bTriggerUsage; -+ __u8 bControlSize; -+ __u8 bmaControls[]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p)) -+ -+#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ -+ uvc_input_header_descriptor_##n_##p -+ -+#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \ -+struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bNumFormats; \ -+ __u16 wTotalLength; \ -+ __u8 bEndpointAddress; \ -+ __u8 bmInfo; \ -+ __u8 bTerminalLink; \ -+ __u8 bStillCaptureMethod; \ -+ __u8 bTriggerSupport; \ -+ __u8 bTriggerUsage; \ -+ __u8 bControlSize; \ -+ __u8 bmaControls[p][n]; \ -+} __attribute__ ((packed)) -+ -+/* 3.9.2.2. Output Header Descriptor */ -+struct uvc_output_header_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bNumFormats; -+ __u16 wTotalLength; -+ __u8 bEndpointAddress; -+ __u8 bTerminalLink; -+ __u8 bControlSize; -+ __u8 bmaControls[]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p)) -+ -+#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ -+ uvc_output_header_descriptor_##n_##p -+ -+#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \ -+struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bNumFormats; \ -+ __u16 wTotalLength; \ -+ __u8 bEndpointAddress; \ -+ __u8 bTerminalLink; \ -+ __u8 bControlSize; \ -+ __u8 bmaControls[p][n]; \ -+} __attribute__ ((packed)) -+ -+/* 3.9.2.6. Color matching descriptor */ -+struct uvc_color_matching_descriptor { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bColorPrimaries; -+ __u8 bTransferCharacteristics; -+ __u8 bMatrixCoefficients; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_COLOR_MATCHING_SIZE 6 -+ -+/* 4.3.1.1. Video Probe and Commit Controls */ -+struct uvc_streaming_control { -+ __u16 bmHint; -+ __u8 bFormatIndex; -+ __u8 bFrameIndex; -+ __u32 dwFrameInterval; -+ __u16 wKeyFrameRate; -+ __u16 wPFrameRate; -+ __u16 wCompQuality; -+ __u16 wCompWindowSize; -+ __u16 wDelay; -+ __u32 dwMaxVideoFrameSize; -+ __u32 dwMaxPayloadTransferSize; -+ __u32 dwClockFrequency; -+ __u8 bmFramingInfo; -+ __u8 bPreferedVersion; -+ __u8 bMinVersion; -+ __u8 bMaxVersion; -+} __attribute__((__packed__)); -+ -+/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */ -+struct uvc_format_uncompressed { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bFormatIndex; -+ __u8 bNumFrameDescriptors; -+ __u8 guidFormat[16]; -+ __u8 bBitsPerPixel; -+ __u8 bDefaultFrameIndex; -+ __u8 bAspectRatioX; -+ __u8 bAspectRatioY; -+ __u8 bmInterfaceFlags; -+ __u8 bCopyProtect; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27 -+ -+/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */ -+struct uvc_frame_uncompressed { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bFrameIndex; -+ __u8 bmCapabilities; -+ __u16 wWidth; -+ __u16 wHeight; -+ __u32 dwMinBitRate; -+ __u32 dwMaxBitRate; -+ __u32 dwMaxVideoFrameBufferSize; -+ __u32 dwDefaultFrameInterval; -+ __u8 bFrameIntervalType; -+ __u32 dwFrameInterval[]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n)) -+ -+#define UVC_FRAME_UNCOMPRESSED(n) \ -+ uvc_frame_uncompressed_##n -+ -+#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \ -+struct UVC_FRAME_UNCOMPRESSED(n) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bFrameIndex; \ -+ __u8 bmCapabilities; \ -+ __u16 wWidth; \ -+ __u16 wHeight; \ -+ __u32 dwMinBitRate; \ -+ __u32 dwMaxBitRate; \ -+ __u32 dwMaxVideoFrameBufferSize; \ -+ __u32 dwDefaultFrameInterval; \ -+ __u8 bFrameIntervalType; \ -+ __u32 dwFrameInterval[n]; \ -+} __attribute__ ((packed)) -+ -+/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */ -+struct uvc_format_mjpeg { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bFormatIndex; -+ __u8 bNumFrameDescriptors; -+ __u8 bmFlags; -+ __u8 bDefaultFrameIndex; -+ __u8 bAspectRatioX; -+ __u8 bAspectRatioY; -+ __u8 bmInterfaceFlags; -+ __u8 bCopyProtect; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_FORMAT_MJPEG_SIZE 11 -+ -+/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */ -+struct uvc_frame_mjpeg { -+ __u8 bLength; -+ __u8 bDescriptorType; -+ __u8 bDescriptorSubType; -+ __u8 bFrameIndex; -+ __u8 bmCapabilities; -+ __u16 wWidth; -+ __u16 wHeight; -+ __u32 dwMinBitRate; -+ __u32 dwMaxBitRate; -+ __u32 dwMaxVideoFrameBufferSize; -+ __u32 dwDefaultFrameInterval; -+ __u8 bFrameIntervalType; -+ __u32 dwFrameInterval[]; -+} __attribute__((__packed__)); -+ -+#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n)) -+ -+#define UVC_FRAME_MJPEG(n) \ -+ uvc_frame_mjpeg_##n -+ -+#define DECLARE_UVC_FRAME_MJPEG(n) \ -+struct UVC_FRAME_MJPEG(n) { \ -+ __u8 bLength; \ -+ __u8 bDescriptorType; \ -+ __u8 bDescriptorSubType; \ -+ __u8 bFrameIndex; \ -+ __u8 bmCapabilities; \ -+ __u16 wWidth; \ -+ __u16 wHeight; \ -+ __u32 dwMinBitRate; \ -+ __u32 dwMaxBitRate; \ -+ __u32 dwMaxVideoFrameBufferSize; \ -+ __u32 dwDefaultFrameInterval; \ -+ __u8 bFrameIntervalType; \ -+ __u32 dwFrameInterval[n]; \ -+} __attribute__ ((packed)) -+ - #endif /* __LINUX_USB_VIDEO_H */ - |
