summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/class/usblp.c4
-rw-r--r--drivers/usb/core/file.c8
-rw-r--r--drivers/usb/core/usb.c4
-rw-r--r--drivers/usb/gadget/Kconfig28
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/m66592-udc.c286
-rw-r--r--drivers/usb/gadget/m66592-udc.h90
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c1689
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h256
-rw-r--r--drivers/usb/host/Kconfig7
-rw-r--r--drivers/usb/host/r8a66597-hcd.c210
-rw-r--r--drivers/usb/host/r8a66597.h440
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/legousbtower.c4
-rw-r--r--drivers/usb/serial/ark3116.c51
-rw-r--r--drivers/usb/serial/belkin_sa.c4
-rw-r--r--drivers/usb/serial/ch341.c5
-rw-r--r--drivers/usb/serial/console.c32
-rw-r--r--drivers/usb/serial/cp210x.c12
-rw-r--r--drivers/usb/serial/cyberjack.c4
-rw-r--r--drivers/usb/serial/cypress_m8.c18
-rw-r--r--drivers/usb/serial/digi_acceleport.c6
-rw-r--r--drivers/usb/serial/empeg.c18
-rw-r--r--drivers/usb/serial/ftdi_sio.c6
-rw-r--r--drivers/usb/serial/garmin_gps.c3
-rw-r--r--drivers/usb/serial/generic.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c6
-rw-r--r--drivers/usb/serial/io_ti.c3
-rw-r--r--drivers/usb/serial/ipaq.c9
-rw-r--r--drivers/usb/serial/ipw.c3
-rw-r--r--drivers/usb/serial/ir-usb.c6
-rw-r--r--drivers/usb/serial/iuu_phoenix.c34
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/keyspan.h3
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c10
-rw-r--r--drivers/usb/serial/kobil_sct.c28
-rw-r--r--drivers/usb/serial/mct_u232.c15
-rw-r--r--drivers/usb/serial/mos7720.c123
-rw-r--r--drivers/usb/serial/mos7840.c118
-rw-r--r--drivers/usb/serial/navman.c3
-rw-r--r--drivers/usb/serial/omninet.c6
-rw-r--r--drivers/usb/serial/opticon.c3
-rw-r--r--drivers/usb/serial/option.c6
-rw-r--r--drivers/usb/serial/oti6858.c27
-rw-r--r--drivers/usb/serial/pl2303.c5
-rw-r--r--drivers/usb/serial/sierra.c3
-rw-r--r--drivers/usb/serial/spcp8x5.c26
-rw-r--r--drivers/usb/serial/symbolserial.c3
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c6
-rw-r--r--drivers/usb/serial/usb-serial.c385
-rw-r--r--drivers/usb/serial/usb_debug.c5
-rw-r--r--drivers/usb/serial/visor.c6
-rw-r--r--drivers/usb/serial/whiteheat.c11
56 files changed, 2748 insertions, 1316 deletions
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 2bfc41e..85a1a55 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -858,10 +858,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
if (!ACM_READY(acm))
return;
- /* FIXME: Needs to support the tty_baud interface */
- /* FIXME: Broken on sparc */
- newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
- (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
+ newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) +
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 26c09f0..9bc112e 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -1057,14 +1057,14 @@ static const struct file_operations usblp_fops = {
.release = usblp_release,
};
-static char *usblp_nodename(struct device *dev)
+static char *usblp_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
}
static struct usb_class_driver usblp_class = {
.name = "lp%d",
- .nodename = usblp_nodename,
+ .devnode = usblp_devnode,
.fops = &usblp_fops,
.minor_base = USBLP_MINOR_BASE,
};
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 5cef889..222ee07 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -67,14 +67,14 @@ static struct usb_class {
struct class *class;
} *usb_class;
-static char *usb_nodename(struct device *dev)
+static char *usb_devnode(struct device *dev, mode_t *mode)
{
struct usb_class_driver *drv;
drv = dev_get_drvdata(dev);
- if (!drv || !drv->nodename)
+ if (!drv || !drv->devnode)
return NULL;
- return drv->nodename(dev);
+ return drv->devnode(dev, mode);
}
static int init_usb_class(void)
@@ -100,7 +100,7 @@ static int init_usb_class(void)
kfree(usb_class);
usb_class = NULL;
}
- usb_class->class->nodename = usb_nodename;
+ usb_class->class->devnode = usb_devnode;
exit:
return result;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index a26f738..43ee943 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -311,7 +311,7 @@ static struct dev_pm_ops usb_device_pm_ops = {
#endif /* CONFIG_PM */
-static char *usb_nodename(struct device *dev)
+static char *usb_devnode(struct device *dev, mode_t *mode)
{
struct usb_device *usb_dev;
@@ -324,7 +324,7 @@ struct device_type usb_device_type = {
.name = "usb_device",
.release = usb_release_dev,
.uevent = usb_dev_uevent,
- .nodename = usb_nodename,
+ .devnode = usb_devnode,
.pm = &usb_device_pm_ops,
};
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7f8e83a..9f986b4 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -251,6 +251,24 @@ config USB_PXA25X_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
+config USB_GADGET_R8A66597
+ boolean "Renesas R8A66597 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
+ help
+ R8A66597 is a discrete USB host and peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has nine configurable endpoints, and endpoint zero.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "r8a66597_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_R8A66597
+ tristate
+ depends on USB_GADGET_R8A66597
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_PXA27X
boolean "PXA 27x"
depends on ARCH_PXA && (PXA27x || PXA3xx)
@@ -360,16 +378,6 @@ config USB_M66592
default USB_GADGET
select USB_GADGET_SELECTED
-config SUPERH_BUILT_IN_M66592
- boolean "Enable SuperH built-in USB like the M66592"
- depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
- help
- SH7722 has USB like the M66592.
-
- The transfer rate is very slow when use "Ethernet Gadget".
- However, this problem is improved if change a value of
- NET_IP_ALIGN to 4.
-
#
# Controllers available only in discrete form (and all PCI controllers)
#
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e6017e6b..9d7b87c 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -23,6 +23,7 @@ ifeq ($(CONFIG_ARCH_MXC),y)
fsl_usb2_udc-objs += fsl_mx3_udc.o
endif
obj-$(CONFIG_USB_M66592) += m66592-udc.o
+obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 8e0e9a0..f2d270b 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -173,6 +173,12 @@
// CONFIG_USB_GADGET_AU1X00
// ...
+#ifdef CONFIG_USB_GADGET_R8A66597
+#define gadget_is_r8a66597(g) !strcmp("r8a66597_udc", (g)->name)
+#else
+#define gadget_is_r8a66597(g) 0
+#endif
+
/**
* usb_gadget_controller_number - support bcdDevice id convention
@@ -239,6 +245,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x23;
else if (gadget_is_langwell(gadget))
return 0x24;
+ else if (gadget_is_r8a66597(gadget))
+ return 0x25;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 43dcf9e..a8c8543 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -25,44 +25,18 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/platform_device.h>
-
+#include <linux/err.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include "m66592-udc.h"
-
MODULE_DESCRIPTION("M66592 USB gadget driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:m66592_udc");
-#define DRIVER_VERSION "18 Oct 2007"
-
-/* module parameters */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-static unsigned short endian = M66592_LITTLE;
-module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
-#else
-static unsigned short clock = M66592_XTAL24;
-module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
- "(default=16384)");
-
-static unsigned short vif = M66592_LDRV;
-module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
-
-static unsigned short endian;
-module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
-
-static unsigned short irq_sense = M66592_INTL;
-module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
- "(default=2)");
-#endif
+#define DRIVER_VERSION "21 July 2009"
static const char udc_name[] = "m66592_udc";
static const char *m66592_ep_name[] = {
@@ -244,6 +218,7 @@ static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
{
struct m66592_ep *ep = m66592->pipenum2ep[pipenum];
+ unsigned short mbw;
if (ep->use_dma)
return;
@@ -252,7 +227,12 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
ndelay(450);
- m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ if (m66592->pdata->on_chip)
+ mbw = M66592_MBW_32;
+ else
+ mbw = M66592_MBW_16;
+
+ m66592_bset(m66592, mbw, ep->fifosel);
}
static int pipe_buffer_setting(struct m66592 *m66592,
@@ -276,24 +256,27 @@ static int pipe_buffer_setting(struct m66592 *m66592,
buf_bsize = 0;
break;
case M66592_BULK:
- bufnum = m66592->bi_bufnum +
- (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
- m66592->bi_bufnum += 16;
+ /* isochronous pipes may be used as bulk pipes */
+ if (info->pipe > M66592_BASE_PIPENUM_BULK)
+ bufnum = info->pipe - M66592_BASE_PIPENUM_BULK;
+ else
+ bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC;
+
+ bufnum = M66592_BASE_BUFNUM + (bufnum * 16);
buf_bsize = 7;
pipecfg |= M66592_DBLB;
if (!info->dir_in)
pipecfg |= M66592_SHTNAK;
break;
case M66592_ISO:
- bufnum = m66592->bi_bufnum +
+ bufnum = M66592_BASE_BUFNUM +
(info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
- m66592->bi_bufnum += 16;
buf_bsize = 7;
break;
}
- if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
- pr_err("m66592 pipe memory is insufficient(%d)\n",
- m66592->bi_bufnum);
+
+ if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) {
+ pr_err("m66592 pipe memory is insufficient\n");
return -ENOMEM;
}
@@ -313,17 +296,6 @@ static void pipe_buffer_release(struct m66592 *m66592,
if (info->pipe == 0)
return;
- switch (info->type) {
- case M66592_BULK:
- if (is_bulk_pipe(info->pipe))
- m66592->bi_bufnum -= 16;
- break;
- case M66592_ISO:
- if (is_isoc_pipe(info->pipe))
- m66592->bi_bufnum -= 16;
- break;
- }
-
if (is_bulk_pipe(info->pipe)) {
m66592->bulk--;
} else if (is_interrupt_pipe(info->pipe))
@@ -340,6 +312,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
static void pipe_initialize(struct m66592_ep *ep)
{
struct m66592 *m66592 = ep->m66592;
+ unsigned short mbw;
m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel);
@@ -351,7 +324,12 @@ static void pipe_initialize(struct m66592_ep *ep)
ndelay(450);
- m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ if (m66592->pdata->on_chip)
+ mbw = M66592_MBW_32;
+ else
+ mbw = M66592_MBW_16;
+
+ m66592_bset(m66592, mbw, ep->fifosel);
}
}
@@ -367,15 +345,13 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
ep->fifosel = M66592_D0FIFOSEL;
ep->fifoctr = M66592_D0FIFOCTR;
ep->fifotrn = M66592_D0FIFOTRN;
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
- } else if (m66592->num_dma == 1) {
+ } else if (!m66592->pdata->on_chip && m66592->num_dma == 1) {
m66592->num_dma++;
ep->use_dma = 1;
ep->fifoaddr = M66592_D1FIFO;
ep->fifosel = M66592_D1FIFOSEL;
ep->fifoctr = M66592_D1FIFOCTR;
ep->fifotrn = M66592_D1FIFOTRN;
-#endif
} else {
ep->use_dma = 0;
ep->fifoaddr = M66592_CFIFO;
@@ -620,76 +596,120 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
}
}
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
static void init_controller(struct m66592 *m66592)
{
- m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
- m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
- m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+ unsigned int endian;
- /* This is a workaound for SH7722 2nd cut */
- m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
- m66592_bset(m66592, 0x1000, M66592_TESTMODE);
- m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
+ if (m66592->pdata->on_chip) {
+ if (m66592->pdata->endian)
+ endian = 0; /* big endian */
+ else
+ endian = M66592_LITTLE; /* little endian */
- m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_write(m66592, 0, M66592_CFBCFG);
- m66592_write(m66592, 0, M66592_D0FBCFG);
- m66592_bset(m66592, endian, M66592_CFBCFG);
- m66592_bset(m66592, endian, M66592_D0FBCFG);
-}
-#else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
-static void init_controller(struct m66592 *m66592)
-{
- m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
- M66592_PINCFG);
- m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
- m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
+ /* This is a workaound for SH7722 2nd cut */
+ m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
+ m66592_bset(m66592, 0x1000, M66592_TESTMODE);
+ m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
- m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
- m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
- m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+
+ m66592_write(m66592, 0, M66592_CFBCFG);
+ m66592_write(m66592, 0, M66592_D0FBCFG);
+ m66592_bset(m66592, endian, M66592_CFBCFG);
+ m66592_bset(m66592, endian, M66592_D0FBCFG);
+ } else {
+ unsigned int clock, vif, irq_sense;
+
+ if (m66592->pdata->endian)
+ endian = M66592_BIGEND; /* big endian */
+ else
+ endian = 0; /* little endian */
+
+ if (m66592->pdata->vif)
+ vif = M66592_LDRV; /* 3.3v */
+ else
+ vif = 0; /* 1.5v */
+
+ switch (m66592->pdata->xtal) {
+ case M66592_PLATDATA_XTAL_12MHZ:
+ clock = M66592_XTAL12;
+ break;
+ case M66592_PLATDATA_XTAL_24MHZ:
+ clock = M66592_XTAL24;
+ break;
+ case M66592_PLATDATA_XTAL_48MHZ:
+ clock = M66592_XTAL48;
+ break;
+ default:
+ pr_warning("m66592-udc: xtal configuration error\n");
+ clock = 0;
+ }
+
+ switch (m66592->irq_trigger) {
+ case IRQF_TRIGGER_LOW:
+ irq_sense = M66592_INTL;
+ break;
+ case IRQF_TRIGGER_FALLING:
+ irq_sense = 0;
+ break;
+ default:
+ pr_warning("m66592-udc: irq trigger config error\n");
+ irq_sense = 0;
+ }
- m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+ m66592_bset(m66592,
+ (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+ M66592_PINCFG);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL,
+ M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
- msleep(3);
+ msleep(3);
- m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
- msleep(1);
+ msleep(1);
- m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
- m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
- m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
- M66592_DMA0CFG);
+ m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
+ m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+ M66592_DMA0CFG);
+ }
}
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
static void disable_controller(struct m66592 *m66592)
{
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
- m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
- udelay(1);
- m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
-#endif
+ if (!m66592->pdata->on_chip) {
+ m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+ }
}
static void m66592_start_xclock(struct m66592 *m66592)
{
-#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
u16 tmp;
- tmp = m66592_read(m66592, M66592_SYSCFG);
- if (!(tmp & M66592_XCKE))
- m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
-#endif
+ if (!m66592->pdata->on_chip) {
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_XCKE))
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+ }
}
/*-------------------------------------------------------------------------*/
@@ -1177,8 +1197,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- if (!intsts0 && !intenb0) {
+ if (m66592->pdata->on_chip && !intsts0 && !intenb0) {
/*
* When USB clock stops, it cannot read register. Even if a
* clock stops, the interrupt occurs. So this driver turn on
@@ -1188,7 +1207,6 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
}
-#endif
savepipe = m66592_read(m66592, M66592_CFIFOSEL);
@@ -1534,9 +1552,11 @@ static int __exit m66592_remove(struct platform_device *pdev)
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- clk_disable(m66592->clk);
- clk_put(m66592->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ clk_disable(m66592->clk);
+ clk_put(m66592->clk);
+ }
#endif
kfree(m66592);
return 0;
@@ -1548,11 +1568,10 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r)
static int __init m66592_probe(struct platform_device *pdev)
{
- struct resource *res;
- int irq;
+ struct resource *res, *ires;
void __iomem *reg = NULL;
struct m66592 *m66592 = NULL;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
char clk_name[8];
#endif
int ret = 0;
@@ -1565,10 +1584,11 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!ires) {
ret = -ENODEV;
- pr_err("platform_get_irq error.\n");
+ dev_err(&pdev->dev,
+ "platform_get_resource IORESOURCE_IRQ error.\n");
goto clean_up;
}
@@ -1579,6 +1599,12 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ ret = -ENODEV;
+ goto clean_up;
+ }
+
/* initialize ucd */
m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
if (m66592 == NULL) {
@@ -1586,6 +1612,9 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
+ m66592->pdata = pdev->dev.platform_data;
+ m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
+
spin_lock_init(&m66592->lock);
dev_set_drvdata(&pdev->dev, m66592);
@@ -1603,24 +1632,25 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->timer.data = (unsigned long)m66592;
m66592->reg = reg;
- m66592->bi_bufnum = M66592_BASE_BUFNUM;
-
- ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ ret = request_irq(ires->start, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
udc_name, m66592);
if (ret < 0) {
pr_err("request_irq error (%d)\n", ret);
goto clean_up;
}
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
- m66592->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(m66592->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(m66592->clk);
- goto clean_up2;
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id);
+ m66592->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(m66592->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+ clk_name);
+ ret = PTR_ERR(m66592->clk);
+ goto clean_up2;
+ }
+ clk_enable(m66592->clk);
}
- clk_enable(m66592->clk);
#endif
INIT_LIST_HEAD(&m66592->gadget.ep_list);
m66592->gadget.ep0 = &m66592->ep[0].ep;
@@ -1662,12 +1692,14 @@ static int __init m66592_probe(struct platform_device *pdev)
return 0;
clean_up3:
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
- clk_disable(m66592->clk);
- clk_put(m66592->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (m66592->pdata->on_chip) {
+ clk_disable(m66592->clk);
+ clk_put(m66592->clk);
+ }
clean_up2:
#endif
- free_irq(irq, m66592);
+ free_irq(ires->start, m66592);
clean_up:
if (m66592) {
if (m66592->ep0_req)
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 286ce07..8b960de 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -23,10 +23,12 @@
#ifndef __M66592_UDC_H__
#define __M66592_UDC_H__
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
#include <linux/clk.h>
#endif
+#include <linux/usb/m66592.h>
+
#define M66592_SYSCFG 0x00
#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
#define M66592_XTAL48 0x8000 /* 48MHz */
@@ -76,11 +78,11 @@
#define M66592_P_TST_J 0x0001 /* PERI TEST J */
#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+/* built-in registers */
#define M66592_CFBCFG 0x0A
#define M66592_D0FBCFG 0x0C
#define M66592_LITTLE 0x0100 /* b8: Little endian mode */
-#else
+/* external chip case */
#define M66592_PINCFG 0x0A
#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
@@ -100,8 +102,8 @@
#define M66592_PKTM 0x0020 /* b5: Packet mode */
#define M66592_DENDE 0x0010 /* b4: Dend enable */
#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+/* common case */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
#define M66592_D1FIFO 0x18
@@ -113,13 +115,9 @@
#define M66592_REW 0x4000 /* b14: Buffer rewind */
#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
-#define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */
-#else
-#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
-#define M66592_MBW_8 0x0000 /* 8bit */
-#define M66592_MBW_16 0x0400 /* 16bit */
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#define M66592_MBW_32 0x0800 /* 32bit */
#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
@@ -480,9 +478,11 @@ struct m66592_ep {
struct m66592 {
spinlock_t lock;
void __iomem *reg;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
+ struct m66592_platdata *pdata;
+ unsigned long irq_trigger;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
@@ -506,7 +506,6 @@ struct m66592 {
int interrupt;
int isochronous;
int num_dma;
- int bi_bufnum; /* bulk and isochronous's bufnum */
};
#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
@@ -547,13 +546,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592,
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- len = (len + 3) / 4;
- insl(fifoaddr, buf, len);
-#else
- len = (len + 1) / 2;
- insw(fifoaddr, buf, len);
-#endif
+ if (m66592->pdata->on_chip) {
+ len = (len + 3) / 4;
+ insl(fifoaddr, buf, len);
+ } else {
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
+ }
}
static inline void m66592_write(struct m66592 *m66592, u16 val,
@@ -567,33 +566,34 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
-#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
- unsigned long count;
- unsigned char *pb;
- int i;
-
- count = len / 4;
- outsl(fifoaddr, buf, count);
-
- if (len & 0x00000003) {
- pb = buf + count * 4;
- for (i = 0; i < (len & 0x00000003); i++) {
- if (m66592_read(m66592, M66592_CFBCFG)) /* little */
- outb(pb[i], fifoaddr + (3 - i));
- else
- outb(pb[i], fifoaddr + i);
+
+ if (m66592->pdata->on_chip) {
+ unsigned long count;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (m66592_read(m66592, M66592_CFBCFG)) /* le */
+ outb(pb[i], fifoaddr + (3 - i));
+ else
+ outb(pb[i], fifoaddr + i);
+ }
+ }
+ } else {
+ unsigned long odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (odd) {
+ unsigned char *p = buf + len*2;
+ outb(*p, fifoaddr);
}
}
-#else
- unsigned long odd = len & 0x0001;
-
- len = len / 2;
- outsw(fifoaddr, buf, len);
- if (odd) {
- unsigned char *p = buf + len*2;
- outb(*p, fifoaddr);
- }
-#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
new file mode 100644
index 0000000..e220fb8
--- /dev/null
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -0,0 +1,1689 @@
+/*
+ * R8A66597 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2009 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "r8a66597-udc.h"
+
+#define DRIVER_VERSION "2009-08-18"
+
+static const char udc_name[] = "r8a66597_udc";
+static const char *r8a66597_ep_name[] = {
+ "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7",
+ "ep8", "ep9",
+};
+
+static void disable_controller(struct r8a66597 *r8a66597);
+static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req);
+static void irq_packet_write(struct r8a66597_ep *ep,
+ struct r8a66597_request *req);
+static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags);
+
+static void transfer_complete(struct r8a66597_ep *ep,
+ struct r8a66597_request *req, int status);
+
+/*-------------------------------------------------------------------------*/
+static inline u16 get_usb_speed(struct r8a66597 *r8a66597)
+{
+ return r8a66597_read(r8a66597, DVSTCTR0) & RHST;
+}
+
+static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, INTENB0);
+ r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE,
+ INTENB0);
+ r8a66597_bset(r8a66597, (1 << pipenum), reg);
+ r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, INTENB0);
+ r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE,
+ INTENB0);
+ r8a66597_bclr(r8a66597, (1 << pipenum), reg);
+ r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+static void r8a66597_usb_connect(struct r8a66597 *r8a66597)
+{
+ r8a66597_bset(r8a66597, CTRE, INTENB0);
+ r8a66597_bset(r8a66597, BEMPE | BRDYE, INTENB0);
+
+ r8a66597_bset(r8a66597, DPRPU, SYSCFG0);
+}
+
+static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
+{
+ r8a66597_bclr(r8a66597, CTRE, INTENB0);
+ r8a66597_bclr(r8a66597, BEMPE | BRDYE, INTENB0);
+ r8a66597_bclr(r8a66597, DPRPU, SYSCFG0);
+
+ r8a66597->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock(&r8a66597->lock);
+ r8a66597->driver->disconnect(&r8a66597->gadget);
+ spin_lock(&r8a66597->lock);
+
+ disable_controller(r8a66597);
+ INIT_LIST_HEAD(&r8a66597->ep[0].queue);
+}
+
+static inline u16 control_reg_get_pid(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ u16 pid = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ pid = r8a66597_read(r8a66597, DCPCTR) & PID;
+ else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ pid = r8a66597_read(r8a66597, offset) & PID;
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return pid;
+}
+
+static inline void control_reg_set_pid(struct r8a66597 *r8a66597, u16 pipenum,
+ u16 pid)
+{
+ unsigned long offset;
+
+ if (pipenum == 0)
+ r8a66597_mdfy(r8a66597, pid, PID, DCPCTR);
+ else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ r8a66597_mdfy(r8a66597, pid, PID, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+}
+
+static inline void pipe_start(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ control_reg_set_pid(r8a66597, pipenum, PID_BUF);
+}
+
+static inline void pipe_stop(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ control_reg_set_pid(r8a66597, pipenum, PID_NAK);
+}
+
+static inline void pipe_stall(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ control_reg_set_pid(r8a66597, pipenum, PID_STALL);
+}
+
+static inline u16 control_reg_get(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ u16 ret = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ ret = r8a66597_read(r8a66597, DCPCTR);
+ else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ ret = r8a66597_read(r8a66597, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return ret;
+}
+
+static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ unsigned long offset;
+
+ pipe_stop(r8a66597, pipenum);
+
+ if (pipenum == 0)
+ r8a66597_bset(r8a66597, SQCLR, DCPCTR);
+ else if (pipenum < R8A66597_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ r8a66597_bset(r8a66597, SQCLR, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+}
+
+static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ u16 tmp;
+ int size;
+
+ if (pipenum == 0) {
+ tmp = r8a66597_read(r8a66597, DCPCFG);
+ if ((tmp & R8A66597_CNTMD) != 0)
+ size = 256;
+ else {
+ tmp = r8a66597_read(r8a66597, DCPMAXP);
+ size = tmp & MAXP;
+ }
+ } else {
+ r8a66597_write(r8a66597, pipenum, PIPESEL);
+ tmp = r8a66597_read(r8a66597, PIPECFG);
+ if ((tmp & R8A66597_CNTMD) != 0) {
+ tmp = r8a66597_read(r8a66597, PIPEBUF);
+ size = ((tmp >> 10) + 1) * 64;
+ } else {
+ tmp = r8a66597_read(r8a66597, PIPEMAXP);
+ size = tmp & MXPS;
+ }
+ }
+
+ return size;
+}
+
+static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
+{
+ if (r8a66597->pdata->on_chip)
+ return MBW_32;
+ else
+ return MBW_16;
+}
+
+static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum];
+
+ if (ep->use_dma)
+ return;
+
+ r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
+}
+
+static int pipe_buffer_setting(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe_info *info)
+{
+ u16 bufnum = 0, buf_bsize = 0;
+ u16 pipecfg = 0;
+
+ if (info->pipe == 0)
+ return -EINVAL;
+
+ r8a66597_write(r8a66597, info->pipe, PIPESEL);
+
+ if (info->dir_in)
+ pipecfg |= R8A66597_DIR;
+ pipecfg |= info->type;
+ pipecfg |= info->epnum;
+ switch (info->type) {
+ case R8A66597_INT:
+ bufnum = 4 + (info->pipe - R8A66597_BASE_PIPENUM_INT);
+ buf_bsize = 0;
+ break;
+ case R8A66597_BULK:
+ /* isochronous pipes may be used as bulk pipes */
+ if (info->pipe > R8A66597_BASE_PIPENUM_BULK)
+ bufnum = info->pipe - R8A66597_BASE_PIPENUM_BULK;
+ else
+ bufnum = info->pipe - R8A66597_BASE_PIPENUM_ISOC;
+
+ bufnum = R8A66597_BASE_BUFNUM + (bufnum * 16);
+ buf_bsize = 7;
+ pipecfg |= R8A66597_DBLB;
+ if (!info->dir_in)
+ pipecfg |= R8A66597_SHTNAK;
+ break;
+ case R8A66597_ISO:
+ bufnum = R8A66597_BASE_BUFNUM +
+ (info->pipe - R8A66597_BASE_PIPENUM_ISOC) * 16;
+ buf_bsize = 7;
+ break;
+ }
+
+ if (buf_bsize && ((bufnum + 16) >= R8A66597_MAX_BUFNUM)) {
+ pr_err(KERN_ERR "r8a66597 pipe memory is insufficient\n");
+ return -ENOMEM;
+ }
+
+ r8a66597_write(r8a66597, pipecfg, PIPECFG);
+ r8a66597_write(r8a66597, (buf_bsize << 10) | (bufnum), PIPEBUF);
+ r8a66597_write(r8a66597, info->maxpacket, PIPEMAXP);
+ if (info->interval)
+ info->interval--;
+ r8a66597_write(r8a66597, info->interval, PIPEPERI);
+
+ return 0;
+}
+
+static void pipe_buffer_release(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe_info *info)
+{
+ if (info->pipe == 0)
+ return;
+
+ if (is_bulk_pipe(info->pipe))
+ r8a66597->bulk--;
+ else if (is_interrupt_pipe(info->pipe))
+ r8a66597->interrupt--;
+ else if (is_isoc_pipe(info->pipe)) {
+ r8a66597->isochronous--;
+ if (info->type == R8A66597_BULK)
+ r8a66597->bulk--;
+ } else
+ printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+ info->pipe);
+}
+
+static void pipe_initialize(struct r8a66597_ep *ep)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+
+ r8a66597_mdfy(r8a66597, 0, CURPIPE, ep->fifosel);
+
+ r8a66597_write(r8a66597, ACLRM, ep->pipectr);
+ r8a66597_write(r8a66597, 0, ep->pipectr);
+ r8a66597_write(r8a66597, SQCLR, ep->pipectr);
+ if (ep->use_dma) {
+ r8a66597_mdfy(r8a66597, ep->pipenum, CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel);
+ }
+}
+
+static void r8a66597_ep_setting(struct r8a66597 *r8a66597,
+ struct r8a66597_ep *ep,
+ const struct usb_endpoint_descriptor *desc,
+ u16 pipenum, int dma)
+{
+ ep->use_dma = 0;
+ ep->fifoaddr = CFIFO;
+ ep->fifosel = CFIFOSEL;
+ ep->fifoctr = CFIFOCTR;
+ ep->fifotrn = 0;
+
+ ep->pipectr = get_pipectr_addr(pipenum);
+ ep->pipenum = pipenum;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ r8a66597->pipenum2ep[pipenum] = ep;
+ r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK]
+ = ep;
+ INIT_LIST_HEAD(&ep->queue);
+}
+
+static void r8a66597_ep_release(struct r8a66597_ep *ep)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ u16 pipenum = ep->pipenum;
+
+ if (pipenum == 0)
+ return;
+
+ if (ep->use_dma)
+ r8a66597->num_dma--;
+ ep->pipenum = 0;
+ ep->busy = 0;
+ ep->use_dma = 0;
+}
+
+static int alloc_pipe_config(struct r8a66597_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ struct r8a66597_pipe_info info;
+ int dma = 0;
+ unsigned char *counter;
+ int ret;
+
+ ep->desc = desc;
+
+ if (ep->pipenum) /* already allocated pipe */
+ return 0;
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (r8a66597->bulk >= R8A66597_MAX_NUM_BULK) {
+ if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) {
+ printk(KERN_ERR "bulk pipe is insufficient\n");
+ return -ENODEV;
+ } else {
+ info.pipe = R8A66597_BASE_PIPENUM_ISOC
+ + r8a66597->isochronous;
+ counter = &r8a66597->isochronous;
+ }
+ } else {
+ info.pipe = R8A66597_BASE_PIPENUM_BULK + r8a66597->bulk;
+ counter = &r8a66597->bulk;
+ }
+ info.type = R8A66597_BULK;
+ dma = 1;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (r8a66597->interrupt >= R8A66597_MAX_NUM_INT) {
+ printk(KERN_ERR "interrupt pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = R8A66597_BASE_PIPENUM_INT + r8a66597->interrupt;
+ info.type = R8A66597_INT;
+ counter = &r8a66597->interrupt;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) {
+ printk(KERN_ERR "isochronous pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = R8A66597_BASE_PIPENUM_ISOC + r8a66597->isochronous;
+ info.type = R8A66597_ISO;
+ counter = &r8a66597->isochronous;
+ break;
+ default:
+ printk(KERN_ERR "unexpect xfer type\n");
+ return -EINVAL;
+ }
+ ep->type = info.type;
+
+ info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.interval = desc->bInterval;
+ if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ info.dir_in = 1;
+ else
+ info.dir_in = 0;
+
+ ret = pipe_buffer_setting(r8a66597, &info);
+ if (ret < 0) {
+ printk(KERN_ERR "pipe_buffer_setting fail\n");
+ return ret;
+ }
+
+ (*counter)++;
+ if ((counter == &r8a66597->isochronous) && info.type == R8A66597_BULK)
+ r8a66597->bulk++;
+
+ r8a66597_ep_setting(r8a66597, ep, desc, info.pipe, dma);
+ pipe_initialize(ep);
+
+ return 0;
+}
+
+static int free_pipe_config(struct r8a66597_ep *ep)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ struct r8a66597_pipe_info info;
+
+ info.pipe = ep->pipenum;
+ info.type = ep->type;
+ pipe_buffer_release(r8a66597, &info);
+ r8a66597_ep_release(ep);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static void pipe_irq_enable(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ enable_irq_ready(r8a66597, pipenum);
+ enable_irq_nrdy(r8a66597, pipenum);
+}
+
+static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ disable_irq_ready(r8a66597, pipenum);
+ disable_irq_nrdy(r8a66597, pipenum);
+}
+
+/* if complete is true, gadget driver complete function is not call */
+static void control_end(struct r8a66597 *r8a66597, unsigned ccpl)
+{
+ r8a66597->ep[0].internal_ccpl = ccpl;
+ pipe_start(r8a66597, 0);
+ r8a66597_bset(r8a66597, CCPL, DCPCTR);
+}
+
+static void start_ep0_write(struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+
+ pipe_change(r8a66597, ep->pipenum);
+ r8a66597_mdfy(r8a66597, ISEL, (ISEL | CURPIPE), CFIFOSEL);
+ r8a66597_write(r8a66597, BCLR, ep->fifoctr);
+ if (req->req.length == 0) {
+ r8a66597_bset(r8a66597, BVAL, ep->fifoctr);
+ pipe_start(r8a66597, 0);
+ transfer_complete(ep, req, 0);
+ } else {
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ irq_ep0_write(ep, req);
+ }
+}
+
+static void start_packet_write(struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ u16 tmp;
+
+ pipe_change(r8a66597, ep->pipenum);
+ disable_irq_empty(r8a66597, ep->pipenum);
+ pipe_start(r8a66597, ep->pipenum);
+
+ tmp = r8a66597_read(r8a66597, ep->fifoctr);
+ if (unlikely((tmp & FRDY) == 0))
+ pipe_irq_enable(r8a66597, ep->pipenum);
+ else
+ irq_packet_write(ep, req);
+}
+
+static void start_packet_read(struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ u16 pipenum = ep->pipenum;
+
+ if (ep->pipenum == 0) {
+ r8a66597_mdfy(r8a66597, 0, (ISEL | CURPIPE), CFIFOSEL);
+ r8a66597_write(r8a66597, BCLR, ep->fifoctr);
+ pipe_start(r8a66597, pipenum);
+ pipe_irq_enable(r8a66597, pipenum);
+ } else {
+ if (ep->use_dma) {
+ r8a66597_bset(r8a66597, TRCLR, ep->fifosel);
+ pipe_change(r8a66597, pipenum);
+ r8a66597_bset(r8a66597, TRENB, ep->fifosel);
+ r8a66597_write(r8a66597,
+ (req->req.length + ep->ep.maxpacket - 1)
+ / ep->ep.maxpacket,
+ ep->fifotrn);
+ }
+ pipe_start(r8a66597, pipenum); /* trigger once */
+ pipe_irq_enable(r8a66597, pipenum);
+ }
+}
+
+static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req)
+{
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ start_packet_write(ep, req);
+ else
+ start_packet_read(ep, req);
+}
+
+static void start_ep0(struct r8a66597_ep *ep, struct r8a66597_request *req)
+{
+ u16 ctsq;
+
+ ctsq = r8a66597_read(ep->r8a66597, INTSTS0) & CTSQ;
+
+ switch (ctsq) {
+ case CS_RDDS:
+ start_ep0_write(ep, req);
+ break;
+ case CS_WRDS:
+ start_packet_read(ep, req);
+ break;
+
+ case CS_WRND:
+ control_end(ep->r8a66597, 0);
+ break;
+ default:
+ printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static void init_controller(struct r8a66597 *r8a66597)
+{
+ u16 vif = r8a66597->pdata->vif ? LDRV : 0;
+ u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0;
+ u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
+
+ if (r8a66597->pdata->on_chip) {
+ r8a66597_bset(r8a66597, 0x04, SYSCFG1);
+ r8a66597_bset(r8a66597, HSE, SYSCFG0);
+
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_bclr(r8a66597, DPRPU, SYSCFG0);
+ r8a66597_bset(r8a66597, USBE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, SCKE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, irq_sense, INTENB1);
+ r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR,
+ DMA0CFG);
+ } else {
+ r8a66597_bset(r8a66597, vif | endian, PINCFG);
+ r8a66597_bset(r8a66597, HSE, SYSCFG0); /* High spd */
+ r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata),
+ XTAL, SYSCFG0);
+
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_bclr(r8a66597, DPRPU, SYSCFG0);
+ r8a66597_bset(r8a66597, USBE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+
+ msleep(3);
+
+ r8a66597_bset(r8a66597, PLLC, SYSCFG0);
+
+ msleep(1);
+
+ r8a66597_bset(r8a66597, SCKE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, irq_sense, INTENB1);
+ r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR,
+ DMA0CFG);
+ }
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+ if (r8a66597->pdata->on_chip) {
+ r8a66597_bset(r8a66597, SCKE, SYSCFG0);
+
+ /* disable interrupts */
+ r8a66597_write(r8a66597, 0, INTENB0);
+ r8a66597_write(r8a66597, 0, INTENB1);
+ r8a66597_write(r8a66597, 0, BRDYENB);
+ r8a66597_write(r8a66597, 0, BEMPENB);
+ r8a66597_write(r8a66597, 0, NRDYENB);
+
+ /* clear status */
+ r8a66597_write(r8a66597, 0, BRDYSTS);
+ r8a66597_write(r8a66597, 0, NRDYSTS);
+ r8a66597_write(r8a66597, 0, BEMPSTS);
+
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+
+ } else {
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+ udelay(1);
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ udelay(1);
+ udelay(1);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ }
+}
+
+static void r8a66597_start_xclock(struct r8a66597 *r8a66597)
+{
+ u16 tmp;
+
+ if (!r8a66597->pdata->on_chip) {
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (!(tmp & XCKE))
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ }
+}
+
+static struct r8a66597_request *get_request_from_ep(struct r8a66597_ep *ep)
+{
+ return list_entry(ep->queue.next, struct r8a66597_request, queue);
+}
+
+/*-------------------------------------------------------------------------*/
+static void transfer_complete(struct r8a66597_ep *ep,
+ struct r8a66597_request *req, int status)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
+{
+ int restart = 0;
+
+ if (unlikely(ep->pipenum == 0)) {
+ if (ep->internal_ccpl) {
+ ep->internal_ccpl = 0;
+ return;
+ }
+ }
+
+ list_del_init(&req->queue);
+ if (ep->r8a66597->gadget.speed == USB_SPEED_UNKNOWN)
+ req->req.status = -ESHUTDOWN;
+ else
+ req->req.status = status;
+
+ if (!list_empty(&ep->queue))
+ restart = 1;
+
+ spin_unlock(&ep->r8a66597->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->r8a66597->lock);
+
+ if (restart) {
+ req = get_request_from_ep(ep);
+ if (ep->desc)
+ start_packet(ep, req);
+ }
+}
+
+static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req)
+{
+ int i;
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+
+ pipe_change(r8a66597, pipenum);
+ r8a66597_bset(r8a66597, ISEL, ep->fifosel);
+
+ i = 0;
+ do {
+ tmp = r8a66597_read(r8a66597, ep->fifoctr);
+ if (i++ > 100000) {
+ printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+ "conflict. please power off this controller.");
+ return;
+ }
+ ndelay(1);
+ } while ((tmp & FRDY) == 0);
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(r8a66597, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ if (size > 0)
+ r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size);
+ if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
+ r8a66597_bset(r8a66597, BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(r8a66597, pipenum);
+ disable_irq_empty(r8a66597, pipenum);
+ } else {
+ disable_irq_ready(r8a66597, pipenum);
+ enable_irq_empty(r8a66597, pipenum);
+ }
+ pipe_start(r8a66597, pipenum);
+}
+
+static void irq_packet_write(struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+
+ pipe_change(r8a66597, pipenum);
+ tmp = r8a66597_read(r8a66597, ep->fifoctr);
+ if (unlikely((tmp & FRDY) == 0)) {
+ pipe_stop(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+ return;
+ }
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(r8a66597, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ r8a66597_write_fifo(r8a66597, ep->fifoaddr, buf, size);
+ if ((size == 0)
+ || ((size % ep->ep.maxpacket) != 0)
+ || ((bufsize != ep->ep.maxpacket)
+ && (bufsize > size)))
+ r8a66597_bset(r8a66597, BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(r8a66597, pipenum);
+ enable_irq_empty(r8a66597, pipenum);
+ } else {
+ disable_irq_empty(r8a66597, pipenum);
+ pipe_irq_enable(r8a66597, pipenum);
+ }
+}
+
+static void irq_packet_read(struct r8a66597_ep *ep,
+ struct r8a66597_request *req)
+{
+ u16 tmp;
+ int rcv_len, bufsize, req_len;
+ int size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct r8a66597 *r8a66597 = ep->r8a66597;
+ int finish = 0;
+
+ pipe_change(r8a66597, pipenum);
+ tmp = r8a66597_read(r8a66597, ep->fifoctr);
+ if (unlikely((tmp & FRDY) == 0)) {
+ req->req.status = -EPIPE;
+ pipe_stop(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ printk(KERN_ERR "read fifo not ready");
+ return;
+ }
+
+ /* prepare parameters */
+ rcv_len = tmp & DTLN;
+ bufsize = get_buffer_size(r8a66597, pipenum);
+
+ buf = req->req.buf + req->req.actual;
+ req_len = req->req.length - req->req.actual;
+ if (rcv_len < bufsize)
+ size = min(rcv_len, req_len);
+ else
+ size = min(bufsize, req_len);
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ pipe_stop(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ finish = 1;
+ }
+
+ /* read fifo */
+ if (req->req.buf) {
+ if (size == 0)
+ r8a66597_write(r8a66597, BCLR, ep->fifoctr);
+ else
+ r8a66597_read_fifo(r8a66597, ep->fifoaddr, buf, size);
+
+ }
+
+ if ((ep->pipenum != 0) && finish)
+ transfer_complete(ep, req, 0);
+}
+
+static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb)
+{
+ u16 check;
+ u16 pipenum;
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+
+ if ((status & BRDY0) && (enb & BRDY0)) {
+ r8a66597_write(r8a66597, ~BRDY0, BRDYSTS);
+ r8a66597_mdfy(r8a66597, 0, CURPIPE, CFIFOSEL);
+
+ ep = &r8a66597->ep[0];
+ req = get_request_from_ep(ep);
+ irq_packet_read(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ r8a66597_write(r8a66597, ~check, BRDYSTS);
+ ep = r8a66597->pipenum2ep[pipenum];
+ req = get_request_from_ep(ep);
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ irq_packet_write(ep, req);
+ else
+ irq_packet_read(ep, req);
+ }
+ }
+ }
+}
+
+static void irq_pipe_empty(struct r8a66597 *r8a66597, u16 status, u16 enb)
+{
+ u16 tmp;
+ u16 check;
+ u16 pipenum;
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+
+ if ((status & BEMP0) && (enb & BEMP0)) {
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+
+ ep = &r8a66597->ep[0];
+ req = get_request_from_ep(ep);
+ irq_ep0_write(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ r8a66597_write(r8a66597, ~check, BEMPSTS);
+ tmp = control_reg_get(r8a66597, pipenum);
+ if ((tmp & INBUFM) == 0) {
+ disable_irq_empty(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ pipe_stop(r8a66597, pipenum);
+ ep = r8a66597->pipenum2ep[pipenum];
+ req = get_request_from_ep(ep);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, 0);
+ }
+ }
+ }
+ }
+}
+
+static void get_status(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
+{
+ struct r8a66597_ep *ep;
+ u16 pid;
+ u16 status = 0;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ status = 1 << USB_DEVICE_SELF_POWERED;
+ break;
+ case USB_RECIP_INTERFACE:
+ status = 0;
+ break;
+ case USB_RECIP_ENDPOINT:
+ ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pid = control_reg_get_pid(r8a66597, ep->pipenum);
+ if (pid == PID_STALL)
+ status = 1 << USB_ENDPOINT_HALT;
+ else
+ status = 0;
+ break;
+ default:
+ pipe_stall(r8a66597, 0);
+ return; /* exit */
+ }
+
+ r8a66597->ep0_data = cpu_to_le16(status);
+ r8a66597->ep0_req->buf = &r8a66597->ep0_data;
+ r8a66597->ep0_req->length = 2;
+ /* AV: what happens if we get called again before that gets through? */
+ spin_unlock(&r8a66597->lock);
+ r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_KERNEL);
+ spin_lock(&r8a66597->lock);
+}
+
+static void clear_feature(struct r8a66597 *r8a66597,
+ struct usb_ctrlrequest *ctrl)
+{
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(r8a66597, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(r8a66597, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ if (!ep->wedge) {
+ pipe_stop(r8a66597, ep->pipenum);
+ control_reg_sqclr(r8a66597, ep->pipenum);
+ spin_unlock(&r8a66597->lock);
+ usb_ep_clear_halt(&ep->ep);
+ spin_lock(&r8a66597->lock);
+ }
+
+ control_end(r8a66597, 1);
+
+ req = get_request_from_ep(ep);
+ if (ep->busy) {
+ ep->busy = 0;
+ if (list_empty(&ep->queue))
+ break;
+ start_packet(ep, req);
+ } else if (!list_empty(&ep->queue))
+ pipe_start(r8a66597, ep->pipenum);
+ }
+ break;
+ default:
+ pipe_stall(r8a66597, 0);
+ break;
+ }
+}
+
+static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
+{
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(r8a66597, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(r8a66597, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct r8a66597_ep *ep;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pipe_stall(r8a66597, ep->pipenum);
+
+ control_end(r8a66597, 1);
+ }
+ break;
+ default:
+ pipe_stall(r8a66597, 0);
+ break;
+ }
+}
+
+/* if return value is true, call class driver's setup() */
+static int setup_packet(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
+{
+ u16 *p = (u16 *)ctrl;
+ unsigned long offset = USBREQ;
+ int i, ret = 0;
+
+ /* read fifo */
+ r8a66597_write(r8a66597, ~VALID, INTSTS0);
+
+ for (i = 0; i < 4; i++)
+ p[i] = r8a66597_read(r8a66597, offset + i*2);
+
+ /* check request */
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_STATUS:
+ get_status(r8a66597, ctrl);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ clear_feature(r8a66597, ctrl);
+ break;
+ case USB_REQ_SET_FEATURE:
+ set_feature(r8a66597, ctrl);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ } else
+ ret = 1;
+ return ret;
+}
+
+static void r8a66597_update_usb_speed(struct r8a66597 *r8a66597)
+{
+ u16 speed = get_usb_speed(r8a66597);
+
+ switch (speed) {
+ case HSMODE:
+ r8a66597->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case FSMODE:
+ r8a66597->gadget.speed = USB_SPEED_FULL;
+ break;
+ default:
+ r8a66597->gadget.speed = USB_SPEED_UNKNOWN;
+ printk(KERN_ERR "USB speed unknown\n");
+ }
+}
+
+static void irq_device_state(struct r8a66597 *r8a66597)
+{
+ u16 dvsq;
+
+ dvsq = r8a66597_read(r8a66597, INTSTS0) & DVSQ;
+ r8a66597_write(r8a66597, ~DVST, INTSTS0);
+
+ if (dvsq == DS_DFLT) {
+ /* bus reset */
+ r8a66597->driver->disconnect(&r8a66597->gadget);
+ r8a66597_update_usb_speed(r8a66597);
+ }
+ if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG)
+ r8a66597_update_usb_speed(r8a66597);
+ if ((dvsq == DS_CNFG || dvsq == DS_ADDS)
+ && r8a66597->gadget.speed == USB_SPEED_UNKNOWN)
+ r8a66597_update_usb_speed(r8a66597);
+
+ r8a66597->old_dvsq = dvsq;
+}
+
+static void irq_control_stage(struct r8a66597 *r8a66597)
+__releases(r8a66597->lock)
+__acquires(r8a66597->lock)
+{
+ struct usb_ctrlrequest ctrl;
+ u16 ctsq;
+
+ ctsq = r8a66597_read(r8a66597, INTSTS0) & CTSQ;
+ r8a66597_write(r8a66597, ~CTRT, INTSTS0);
+
+ switch (ctsq) {
+ case CS_IDST: {
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ ep = &r8a66597->ep[0];
+ req = get_request_from_ep(ep);
+ transfer_complete(ep, req, 0);
+ }
+ break;
+
+ case CS_RDDS:
+ case CS_WRDS:
+ case CS_WRND:
+ if (setup_packet(r8a66597, &ctrl)) {
+ spin_unlock(&r8a66597->lock);
+ if (r8a66597->driver->setup(&r8a66597->gadget, &ctrl)
+ < 0)
+ pipe_stall(r8a66597, 0);
+ spin_lock(&r8a66597->lock);
+ }
+ break;
+ case CS_RDSS:
+ case CS_WRSS:
+ control_end(r8a66597, 0);
+ break;
+ default:
+ printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static irqreturn_t r8a66597_irq(int irq, void *_r8a66597)
+{
+ struct r8a66597 *r8a66597 = _r8a66597;
+ u16 intsts0;
+ u16 intenb0;
+ u16 brdysts, nrdysts, bempsts;
+ u16 brdyenb, nrdyenb, bempenb;
+ u16 savepipe;
+ u16 mask0;
+
+ spin_lock(&r8a66597->lock);
+
+ intsts0 = r8a66597_read(r8a66597, INTSTS0);
+ intenb0 = r8a66597_read(r8a66597, INTENB0);
+
+ savepipe = r8a66597_read(r8a66597, CFIFOSEL);
+
+ mask0 = intsts0 & intenb0;
+ if (mask0) {
+ brdysts = r8a66597_read(r8a66597, BRDYSTS);
+ nrdysts = r8a66597_read(r8a66597, NRDYSTS);
+ bempsts = r8a66597_read(r8a66597, BEMPSTS);
+ brdyenb = r8a66597_read(r8a66597, BRDYENB);
+ nrdyenb = r8a66597_read(r8a66597, NRDYENB);
+ bempenb = r8a66597_read(r8a66597, BEMPENB);
+
+ if (mask0 & VBINT) {
+ r8a66597_write(r8a66597, 0xffff & ~VBINT,
+ INTSTS0);
+ r8a66597_start_xclock(r8a66597);
+
+ /* start vbus sampling */
+ r8a66597->old_vbus = r8a66597_read(r8a66597, INTSTS0)
+ & VBSTS;
+ r8a66597->scount = R8A66597_MAX_SAMPLING;
+
+ mod_timer(&r8a66597->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ if (intsts0 & DVSQ)
+ irq_device_state(r8a66597);
+
+ if ((intsts0 & BRDY) && (intenb0 & BRDYE)
+ && (brdysts & brdyenb))
+ irq_pipe_ready(r8a66597, brdysts, brdyenb);
+ if ((intsts0 & BEMP) && (intenb0 & BEMPE)
+ && (bempsts & bempenb))
+ irq_pipe_empty(r8a66597, bempsts, bempenb);
+
+ if (intsts0 & CTRT)
+ irq_control_stage(r8a66597);
+ }
+
+ r8a66597_write(r8a66597, savepipe, CFIFOSEL);
+
+ spin_unlock(&r8a66597->lock);
+ return IRQ_HANDLED;
+}
+
+static void r8a66597_timer(unsigned long _r8a66597)
+{
+ struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+ unsigned long flags;
+ u16 tmp;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (r8a66597->scount > 0) {
+ tmp = r8a66597_read(r8a66597, INTSTS0) & VBSTS;
+ if (tmp == r8a66597->old_vbus) {
+ r8a66597->scount--;
+ if (r8a66597->scount == 0) {
+ if (tmp == VBSTS)
+ r8a66597_usb_connect(r8a66597);
+ else
+ r8a66597_usb_disconnect(r8a66597);
+ } else {
+ mod_timer(&r8a66597->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ } else {
+ r8a66597->scount = R8A66597_MAX_SAMPLING;
+ r8a66597->old_vbus = tmp;
+ mod_timer(&r8a66597->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ }
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+static int r8a66597_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct r8a66597_ep *ep;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ return alloc_pipe_config(ep, desc);
+}
+
+static int r8a66597_disable(struct usb_ep *_ep)
+{
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ BUG_ON(!ep);
+
+ while (!list_empty(&ep->queue)) {
+ req = get_request_from_ep(ep);
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+ }
+
+ pipe_irq_disable(ep->r8a66597, ep->pipenum);
+ return free_pipe_config(ep);
+}
+
+static struct usb_request *r8a66597_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct r8a66597_request *req;
+
+ req = kzalloc(sizeof(struct r8a66597_request), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void r8a66597_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct r8a66597_request *req;
+
+ req = container_of(_req, struct r8a66597_request, req);
+ kfree(req);
+}
+
+static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ unsigned long flags;
+ int request = 0;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ req = container_of(_req, struct r8a66597_request, req);
+
+ if (ep->r8a66597->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+
+ if (list_empty(&ep->queue))
+ request = 1;
+
+ list_add_tail(&req->queue, &ep->queue);
+ req->req.actual = 0;
+ req->req.status = -EINPROGRESS;
+
+ if (ep->desc == NULL) /* control */
+ start_ep0(ep, req);
+ else {
+ if (request && !ep->busy)
+ start_packet(ep, req);
+ }
+
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+
+ return 0;
+}
+
+static int r8a66597_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ req = container_of(_req, struct r8a66597_request, req);
+
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+
+ return 0;
+}
+
+static int r8a66597_set_halt(struct usb_ep *_ep, int value)
+{
+ struct r8a66597_ep *ep;
+ struct r8a66597_request *req;
+ unsigned long flags;
+ int ret = 0;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ req = get_request_from_ep(ep);
+
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ if (value) {
+ ep->busy = 1;
+ pipe_stall(ep->r8a66597, ep->pipenum);
+ } else {
+ ep->busy = 0;
+ ep->wedge = 0;
+ pipe_stop(ep->r8a66597, ep->pipenum);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+ return ret;
+}
+
+static int r8a66597_set_wedge(struct usb_ep *_ep)
+{
+ struct r8a66597_ep *ep;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+
+ if (!ep || !ep->desc)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+ ep->wedge = 1;
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+
+ return usb_ep_set_halt(_ep);
+}
+
+static void r8a66597_fifo_flush(struct usb_ep *_ep)
+{
+ struct r8a66597_ep *ep;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct r8a66597_ep, ep);
+ spin_lock_irqsave(&ep->r8a66597->lock, flags);
+ if (list_empty(&ep->queue) && !ep->busy) {
+ pipe_stop(ep->r8a66597, ep->pipenum);
+ r8a66597_bclr(ep->r8a66597, BCLR, ep->fifoctr);
+ }
+ spin_unlock_irqrestore(&ep->r8a66597->lock, flags);
+}
+
+static struct usb_ep_ops r8a66597_ep_ops = {
+ .enable = r8a66597_enable,
+ .disable = r8a66597_disable,
+
+ .alloc_request = r8a66597_alloc_request,
+ .free_request = r8a66597_free_request,
+
+ .queue = r8a66597_queue,
+ .dequeue = r8a66597_dequeue,
+
+ .set_halt = r8a66597_set_halt,
+ .set_wedge = r8a66597_set_wedge,
+ .fifo_flush = r8a66597_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct r8a66597 *the_controller;
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct r8a66597 *r8a66597 = the_controller;
+ int retval;
+
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
+ return -EINVAL;
+ if (!r8a66597)
+ return -ENODEV;
+ if (r8a66597->driver)
+ return -EBUSY;
+
+ /* hook up the driver */
+ driver->driver.bus = NULL;
+ r8a66597->driver = driver;
+ r8a66597->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&r8a66597->gadget.dev);
+ if (retval) {
+ printk(KERN_ERR "device_add error (%d)\n", retval);
+ goto error;
+ }
+
+ retval = driver->bind(&r8a66597->gadget);
+ if (retval) {
+ printk(KERN_ERR "bind to driver error (%d)\n", retval);
+ device_del(&r8a66597->gadget.dev);
+ goto error;
+ }
+
+ r8a66597_bset(r8a66597, VBSE, INTENB0);
+ if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) {
+ r8a66597_start_xclock(r8a66597);
+ /* start vbus sampling */
+ r8a66597->old_vbus = r8a66597_read(r8a66597,
+ INTSTS0) & VBSTS;
+ r8a66597->scount = R8A66597_MAX_SAMPLING;
+ mod_timer(&r8a66597->timer, jiffies + msecs_to_jiffies(50));
+ }
+
+ return 0;
+
+error:
+ r8a66597->driver = NULL;
+ r8a66597->gadget.dev.driver = NULL;
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct r8a66597 *r8a66597 = the_controller;
+ unsigned long flags;
+
+ if (driver != r8a66597->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)
+ r8a66597_usb_disconnect(r8a66597);
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+
+ r8a66597_bclr(r8a66597, VBSE, INTENB0);
+
+ driver->unbind(&r8a66597->gadget);
+
+ init_controller(r8a66597);
+ disable_controller(r8a66597);
+
+ device_del(&r8a66597->gadget.dev);
+ r8a66597->driver = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+static int r8a66597_get_frame(struct usb_gadget *_gadget)
+{
+ struct r8a66597 *r8a66597 = gadget_to_r8a66597(_gadget);
+ return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
+}
+
+static struct usb_gadget_ops r8a66597_gadget_ops = {
+ .get_frame = r8a66597_get_frame,
+};
+
+static int __exit r8a66597_remove(struct platform_device *pdev)
+{
+ struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+
+ del_timer_sync(&r8a66597->timer);
+ iounmap((void *)r8a66597->reg);
+ free_irq(platform_get_irq(pdev, 0), r8a66597);
+ r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip) {
+ clk_disable(r8a66597->clk);
+ clk_put(r8a66597->clk);
+ }
+#endif
+ kfree(r8a66597);
+ return 0;
+}
+
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
+static int __init r8a66597_probe(struct platform_device *pdev)
+{
+#ifdef CONFIG_HAVE_CLK
+ char clk_name[8];
+#endif
+ struct resource *res, *ires;
+ int irq;
+ void __iomem *reg = NULL;
+ struct r8a66597 *r8a66597 = NULL;
+ int ret = 0;
+ int i;
+ unsigned long irq_trigger;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_resource error.\n");
+ goto clean_up;
+ }
+
+ ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq = ires->start;
+ irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
+
+ if (irq < 0) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_irq error.\n");
+ goto clean_up;
+ }
+
+ reg = ioremap(res->start, resource_size(res));
+ if (reg == NULL) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "ioremap error.\n");
+ goto clean_up;
+ }
+
+ /* initialize ucd */
+ r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);
+ if (r8a66597 == NULL) {
+ printk(KERN_ERR "kzalloc error\n");
+ goto clean_up;
+ }
+
+ spin_lock_init(&r8a66597->lock);
+ dev_set_drvdata(&pdev->dev, r8a66597);
+ r8a66597->pdata = pdev->dev.platform_data;
+ r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
+
+ r8a66597->gadget.ops = &r8a66597_gadget_ops;
+ device_initialize(&r8a66597->gadget.dev);
+ dev_set_name(&r8a66597->gadget.dev, "gadget");
+ r8a66597->gadget.is_dualspeed = 1;
+ r8a66597->gadget.dev.parent = &pdev->dev;
+ r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ r8a66597->gadget.dev.release = pdev->dev.release;
+ r8a66597->gadget.name = udc_name;
+
+ init_timer(&r8a66597->timer);
+ r8a66597->timer.function = r8a66597_timer;
+ r8a66597->timer.data = (unsigned long)r8a66597;
+ r8a66597->reg = (unsigned long)reg;
+
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip) {
+ snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
+ r8a66597->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(r8a66597->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+ clk_name);
+ ret = PTR_ERR(r8a66597->clk);
+ goto clean_up;
+ }
+ clk_enable(r8a66597->clk);
+ }
+#endif
+
+ disable_controller(r8a66597); /* make sure controller is disabled */
+
+ ret = request_irq(irq, r8a66597_irq, IRQF_DISABLED | IRQF_SHARED,
+ udc_name, r8a66597);
+ if (ret < 0) {
+ printk(KERN_ERR "request_irq error (%d)\n", ret);
+ goto clean_up2;
+ }
+
+ INIT_LIST_HEAD(&r8a66597->gadget.ep_list);
+ r8a66597->gadget.ep0 = &r8a66597->ep[0].ep;
+ INIT_LIST_HEAD(&r8a66597->gadget.ep0->ep_list);
+ for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
+ struct r8a66597_ep *ep = &r8a66597->ep[i];
+
+ if (i != 0) {
+ INIT_LIST_HEAD(&r8a66597->ep[i].ep.ep_list);
+ list_add_tail(&r8a66597->ep[i].ep.ep_list,
+ &r8a66597->gadget.ep_list);
+ }
+ ep->r8a66597 = r8a66597;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->ep.name = r8a66597_ep_name[i];
+ ep->ep.ops = &r8a66597_ep_ops;
+ ep->ep.maxpacket = 512;
+ }
+ r8a66597->ep[0].ep.maxpacket = 64;
+ r8a66597->ep[0].pipenum = 0;
+ r8a66597->ep[0].fifoaddr = CFIFO;
+ r8a66597->ep[0].fifosel = CFIFOSEL;
+ r8a66597->ep[0].fifoctr = CFIFOCTR;
+ r8a66597->ep[0].fifotrn = 0;
+ r8a66597->ep[0].pipectr = get_pipectr_addr(0);
+ r8a66597->pipenum2ep[0] = &r8a66597->ep[0];
+ r8a66597->epaddr2ep[0] = &r8a66597->ep[0];
+
+ the_controller = r8a66597;
+
+ r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep,
+ GFP_KERNEL);
+ if (r8a66597->ep0_req == NULL)
+ goto clean_up3;
+ r8a66597->ep0_req->complete = nop_completion;
+
+ init_controller(r8a66597);
+
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
+ return 0;
+
+clean_up3:
+ free_irq(irq, r8a66597);
+clean_up2:
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip) {
+ clk_disable(r8a66597->clk);
+ clk_put(r8a66597->clk);
+ }
+#endif
+clean_up:
+ if (r8a66597) {
+ if (r8a66597->ep0_req)
+ r8a66597_free_request(&r8a66597->ep[0].ep,
+ r8a66597->ep0_req);
+ kfree(r8a66597);
+ }
+ if (reg)
+ iounmap(reg);
+
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver r8a66597_driver = {
+ .remove = __exit_p(r8a66597_remove),
+ .driver = {
+ .name = (char *) udc_name,
+ },
+};
+
+static int __init r8a66597_udc_init(void)
+{
+ return platform_driver_probe(&r8a66597_driver, r8a66597_probe);
+}
+module_init(r8a66597_udc_init);
+
+static void __exit r8a66597_udc_cleanup(void)
+{
+ platform_driver_unregister(&r8a66597_driver);
+}
+module_exit(r8a66597_udc_cleanup);
+
+MODULE_DESCRIPTION("R8A66597 USB gadget driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
new file mode 100644
index 0000000..03087e7
--- /dev/null
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -0,0 +1,256 @@
+/*
+ * R8A66597 UDC
+ *
+ * Copyright (C) 2007-2009 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#ifdef CONFIG_HAVE_CLK
+#include <linux/clk.h>
+#endif
+
+#include <linux/usb/r8a66597.h>
+
+#define R8A66597_MAX_SAMPLING 10
+
+#define R8A66597_MAX_NUM_PIPE 8
+#define R8A66597_MAX_NUM_BULK 3
+#define R8A66597_MAX_NUM_ISOC 2
+#define R8A66597_MAX_NUM_INT 2
+
+#define R8A66597_BASE_PIPENUM_BULK 3
+#define R8A66597_BASE_PIPENUM_ISOC 1
+#define R8A66597_BASE_PIPENUM_INT 6
+
+#define R8A66597_BASE_BUFNUM 6
+#define R8A66597_MAX_BUFNUM 0x4F
+
+#define is_bulk_pipe(pipenum) \
+ ((pipenum >= R8A66597_BASE_PIPENUM_BULK) && \
+ (pipenum < (R8A66597_BASE_PIPENUM_BULK + R8A66597_MAX_NUM_BULK)))
+#define is_interrupt_pipe(pipenum) \
+ ((pipenum >= R8A66597_BASE_PIPENUM_INT) && \
+ (pipenum < (R8A66597_BASE_PIPENUM_INT + R8A66597_MAX_NUM_INT)))
+#define is_isoc_pipe(pipenum) \
+ ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \
+ (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC)))
+
+struct r8a66597_pipe_info {
+ u16 pipe;
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 interval;
+ u16 dir_in;
+};
+
+struct r8a66597_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+struct r8a66597_ep {
+ struct usb_ep ep;
+ struct r8a66597 *r8a66597;
+
+ struct list_head queue;
+ unsigned busy:1;
+ unsigned wedge:1;
+ unsigned internal_ccpl:1; /* use only control */
+
+ /* this member can able to after r8a66597_enable */
+ unsigned use_dma:1;
+ u16 pipenum;
+ u16 type;
+ const struct usb_endpoint_descriptor *desc;
+ /* register address */
+ unsigned char fifoaddr;
+ unsigned char fifosel;
+ unsigned char fifoctr;
+ unsigned char fifotrn;
+ unsigned char pipectr;
+};
+
+struct r8a66597 {
+ spinlock_t lock;
+ unsigned long reg;
+
+#ifdef CONFIG_HAVE_CLK
+ struct clk *clk;
+#endif
+ struct r8a66597_platdata *pdata;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+
+ struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE];
+ struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE];
+ struct r8a66597_ep *epaddr2ep[16];
+
+ struct timer_list timer;
+ struct usb_request *ep0_req; /* for internal request */
+ u16 ep0_data; /* for internal request */
+ u16 old_vbus;
+ u16 scount;
+ u16 old_dvsq;
+
+ /* pipe config */
+ unsigned char bulk;
+ unsigned char interrupt;
+ unsigned char isochronous;
+ unsigned char num_dma;
+
+ unsigned irq_sense_low:1;
+};
+
+#define gadget_to_r8a66597(_gadget) \
+ container_of(_gadget, struct r8a66597, gadget)
+#define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget)
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+ return inw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, u16 *buf,
+ int len)
+{
+ if (r8a66597->pdata->on_chip) {
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ unsigned long count;
+ union {
+ unsigned long dword;
+ unsigned char byte[4];
+ } data;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ insl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ data.dword = inl(fifoaddr);
+ pb = (unsigned char *)buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++)
+ pb[i] = data.byte[i];
+ }
+ } else {
+ len = (len + 1) / 2;
+ insw(r8a66597->reg + offset, buf, len);
+ }
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+ unsigned long offset)
+{
+ outw(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, u16 *buf,
+ int len)
+{
+ unsigned long fifoaddr = r8a66597->reg + offset;
+
+ if (r8a66597->pdata->on_chip) {
+ unsigned long count;
+ unsigned char *pb;
+ int i;
+
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = (unsigned char *)buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+ outb(pb[i], fifoaddr + i);
+ else
+ outb(pb[i], fifoaddr + 3 - i);
+ }
+ }
+ } else {
+ int odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (unlikely(odd)) {
+ buf = &buf[len];
+ outb((unsigned char)*buf, fifoaddr);
+ }
+ }
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+ u16 val, u16 pat, unsigned long offset)
+{
+ u16 tmp;
+ tmp = r8a66597_read(r8a66597, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ r8a66597_write(r8a66597, tmp, offset);
+}
+
+static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
+{
+ u16 clock = 0;
+
+ switch (pdata->xtal) {
+ case R8A66597_PLATDATA_XTAL_12MHZ:
+ clock = XTAL12;
+ break;
+ case R8A66597_PLATDATA_XTAL_24MHZ:
+ clock = XTAL24;
+ break;
+ case R8A66597_PLATDATA_XTAL_48MHZ:
+ clock = XTAL48;
+ break;
+ default:
+ printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
+ break;
+ }
+
+ return clock;
+}
+
+#define r8a66597_bclr(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, val, 0, offset)
+
+#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
+
+#define enable_irq_ready(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define disable_irq_ready(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define enable_irq_empty(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define disable_irq_empty(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define enable_irq_nrdy(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, NRDYENB)
+#define disable_irq_nrdy(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, NRDYENB)
+
+#endif /* __R8A66597_H__ */
+
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 1a920c7..f21ca7d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -336,13 +336,6 @@ config USB_R8A66597_HCD
To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd.
-config SUPERH_ON_CHIP_R8A66597
- boolean "Enable SuperH on-chip R8A66597 USB"
- depends on USB_R8A66597_HCD && (CPU_SUBTYPE_SH7366 || CPU_SUBTYPE_SH7723 || CPU_SUBTYPE_SH7724)
- help
- This driver enables support for the on-chip R8A66597 in the
- SH7366, SH7723 and SH7724 processors.
-
config USB_WHCI_HCD
tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)"
depends on EXPERIMENTAL
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index e18f749..749b537 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -91,43 +91,43 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
u16 tmp;
int i = 0;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
- clk_enable(r8a66597->clk);
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ clk_enable(r8a66597->clk);
#endif
- do {
- r8a66597_write(r8a66597, SCKE, SYSCFG0);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 1000) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & SCKE) != SCKE);
- r8a66597_write(r8a66597, 0x04, 0x02);
-#else
- do {
- r8a66597_write(r8a66597, USBE, SYSCFG0);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 1000) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & USBE) != USBE);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
- r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
- SYSCFG0);
+ do {
+ r8a66597_write(r8a66597, SCKE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+ } else {
+ do {
+ r8a66597_write(r8a66597, USBE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & USBE) != USBE);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata),
+ XTAL, SYSCFG0);
- i = 0;
- r8a66597_bset(r8a66597, XCKE, SYSCFG0);
- do {
- msleep(1);
- tmp = r8a66597_read(r8a66597, SYSCFG0);
- if (i++ > 500) {
- printk(KERN_ERR "r8a66597: register access fail.\n");
- return -ENXIO;
- }
- } while ((tmp & SCKE) != SCKE);
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+ i = 0;
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ do {
+ msleep(1);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 500) {
+ printk(KERN_ERR "r8a66597: reg access fail.\n");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ }
return 0;
}
@@ -136,15 +136,16 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
{
r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
udelay(1);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#if defined(CONFIG_HAVE_CLK)
- clk_disable(r8a66597->clk);
-#endif
-#else
- r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
- r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
- r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ clk_disable(r8a66597->clk);
#endif
+ } else {
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ }
}
static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
@@ -205,7 +206,7 @@ static int enable_controller(struct r8a66597 *r8a66597)
r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_enable_port(r8a66597, port);
return 0;
@@ -218,7 +219,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
r8a66597_write(r8a66597, 0, INTENB0);
r8a66597_write(r8a66597, 0, INTSTS0);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_disable_port(r8a66597, port);
r8a66597_clock_disable(r8a66597);
@@ -249,11 +250,12 @@ static int is_hub_limit(char *devpath)
return ((strlen(devpath) >= 4) ? 1 : 0);
}
-static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
+static void get_port_number(struct r8a66597 *r8a66597,
+ char *devpath, u16 *root_port, u16 *hub_port)
{
if (root_port) {
*root_port = (devpath[0] & 0x0F) - 1;
- if (*root_port >= R8A66597_MAX_ROOT_HUB)
+ if (*root_port >= r8a66597->max_root_hub)
printk(KERN_ERR "r8a66597: Illegal root port number.\n");
}
if (hub_port)
@@ -355,7 +357,8 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
INIT_LIST_HEAD(&dev->device_list);
list_add_tail(&dev->device_list, &r8a66597->child_device);
- get_port_number(urb->dev->devpath, &dev->root_port, &dev->hub_port);
+ get_port_number(r8a66597, urb->dev->devpath,
+ &dev->root_port, &dev->hub_port);
if (!is_child_device(urb->dev->devpath))
r8a66597->root_hub[dev->root_port].dev = dev;
@@ -420,7 +423,7 @@ static void free_usb_address(struct r8a66597 *r8a66597,
list_del(&dev->device_list);
kfree(dev);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
if (r8a66597->root_hub[port].dev == dev) {
r8a66597->root_hub[port].dev = NULL;
break;
@@ -495,10 +498,20 @@ static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
}
+static inline unsigned short mbw_value(struct r8a66597 *r8a66597)
+{
+ if (r8a66597->pdata->on_chip)
+ return MBW_32;
+ else
+ return MBW_16;
+}
+
/* this function must be called with interrupt disabled */
static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
{
- r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+ unsigned short mbw = mbw_value(r8a66597);
+
+ r8a66597_mdfy(r8a66597, mbw | pipenum, mbw | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
}
@@ -506,11 +519,13 @@ static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe)
{
+ unsigned short mbw = mbw_value(r8a66597);
+
cfifo_change(r8a66597, 0);
- r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D0FIFOSEL);
- r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D1FIFOSEL);
+ r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D0FIFOSEL);
+ r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D1FIFOSEL);
- r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE,
+ r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, mbw | CURPIPE,
pipe->fifosel);
r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
}
@@ -742,9 +757,13 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe,
struct urb *urb)
{
-#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
int i;
struct r8a66597_pipe_info *info = &pipe->info;
+ unsigned short mbw = mbw_value(r8a66597);
+
+ /* pipe dma is only for external controlles */
+ if (r8a66597->pdata->on_chip)
+ return;
if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
@@ -763,8 +782,8 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
set_pipe_reg_addr(pipe, i);
cfifo_change(r8a66597, 0);
- r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,
- MBW | CURPIPE, pipe->fifosel);
+ r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum,
+ mbw | CURPIPE, pipe->fifosel);
r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
pipe->info.pipenum);
@@ -772,7 +791,6 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
break;
}
}
-#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
}
/* this function must be called with interrupt disabled */
@@ -1769,7 +1787,7 @@ static void r8a66597_timer(unsigned long _r8a66597)
spin_lock_irqsave(&r8a66597->lock, flags);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ for (port = 0; port < r8a66597->max_root_hub; port++)
r8a66597_root_hub_control(r8a66597, port);
spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -1807,7 +1825,7 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
u16 root_port, hub_port;
if (usb_address == 0) {
- get_port_number(urb->dev->devpath,
+ get_port_number(r8a66597, urb->dev->devpath,
&root_port, &hub_port);
set_devadd_reg(r8a66597, 0,
get_r8a66597_usb_speed(urb->dev->speed),
@@ -2082,7 +2100,7 @@ static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
*buf = 0; /* initialize (no change) */
- for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) {
+ for (i = 0; i < r8a66597->max_root_hub; i++) {
if (r8a66597->root_hub[i].port & 0xffff0000)
*buf |= 1 << (i + 1);
}
@@ -2097,11 +2115,11 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
{
desc->bDescriptorType = 0x29;
desc->bHubContrCurrent = 0;
- desc->bNbrPorts = R8A66597_MAX_ROOT_HUB;
+ desc->bNbrPorts = r8a66597->max_root_hub;
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
desc->wHubCharacteristics = cpu_to_le16(0x0011);
- desc->bitmap[0] = ((1 << R8A66597_MAX_ROOT_HUB) - 1) << 1;
+ desc->bitmap[0] = ((1 << r8a66597->max_root_hub) - 1) << 1;
desc->bitmap[1] = ~0;
}
@@ -2129,7 +2147,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
}
break;
case ClearPortFeature:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
if (wLength != 0)
goto error;
@@ -2162,12 +2180,12 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*buf = 0x00;
break;
case GetPortStatus:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
*(__le32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
- if (wIndex > R8A66597_MAX_ROOT_HUB)
+ if (wIndex > r8a66597->max_root_hub)
goto error;
if (wLength != 0)
goto error;
@@ -2216,7 +2234,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
dbg("%s", __func__);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);
@@ -2247,7 +2265,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
dbg("%s", __func__);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
unsigned long dvstctr_reg = get_dvstctr_reg(port);
@@ -2305,16 +2323,16 @@ static struct hc_driver r8a66597_hc_driver = {
};
#if defined(CONFIG_PM)
-static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
+static int r8a66597_suspend(struct device *dev)
{
- struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
int port;
dbg("%s", __func__);
disable_controller(r8a66597);
- for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
rh->port = 0x00000000;
@@ -2323,9 +2341,9 @@ static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int r8a66597_resume(struct platform_device *pdev)
+static int r8a66597_resume(struct device *dev)
{
- struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
dbg("%s", __func__);
@@ -2335,9 +2353,17 @@ static int r8a66597_resume(struct platform_device *pdev)
return 0;
}
+
+static struct dev_pm_ops r8a66597_dev_pm_ops = {
+ .suspend = r8a66597_suspend,
+ .resume = r8a66597_resume,
+ .poweroff = r8a66597_suspend,
+ .restore = r8a66597_resume,
+};
+
+#define R8A66597_DEV_PM_OPS (&r8a66597_dev_pm_ops)
#else /* if defined(CONFIG_PM) */
-#define r8a66597_suspend NULL
-#define r8a66597_resume NULL
+#define R8A66597_DEV_PM_OPS NULL
#endif
static int __init_or_module r8a66597_remove(struct platform_device *pdev)
@@ -2348,8 +2374,9 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
del_timer_sync(&r8a66597->rh_timer);
usb_remove_hcd(hcd);
iounmap((void *)r8a66597->reg);
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip)
+ clk_put(r8a66597->clk);
#endif
usb_put_hcd(hcd);
return 0;
@@ -2357,7 +2384,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
static int __devinit r8a66597_probe(struct platform_device *pdev)
{
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
char clk_name[8];
#endif
struct resource *res = NULL, *ires;
@@ -2419,15 +2446,20 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
r8a66597->pdata = pdev->dev.platform_data;
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
- r8a66597->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(r8a66597->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(r8a66597->clk);
- goto clean_up2;
- }
+ if (r8a66597->pdata->on_chip) {
+#ifdef CONFIG_HAVE_CLK
+ snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
+ r8a66597->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(r8a66597->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n",
+ clk_name);
+ ret = PTR_ERR(r8a66597->clk);
+ goto clean_up2;
+ }
#endif
+ r8a66597->max_root_hub = 1;
+ } else
+ r8a66597->max_root_hub = 2;
spin_lock_init(&r8a66597->lock);
init_timer(&r8a66597->rh_timer);
@@ -2457,8 +2489,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
return 0;
clean_up3:
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
- clk_put(r8a66597->clk);
+#ifdef CONFIG_HAVE_CLK
+ if (r8a66597->pdata->on_chip)
+ clk_put(r8a66597->clk);
clean_up2:
#endif
usb_put_hcd(hcd);
@@ -2473,11 +2506,10 @@ clean_up:
static struct platform_driver r8a66597_driver = {
.probe = r8a66597_probe,
.remove = r8a66597_remove,
- .suspend = r8a66597_suspend,
- .resume = r8a66597_resume,
.driver = {
.name = (char *) hcd_name,
.owner = THIS_MODULE,
+ .pm = R8A66597_DEV_PM_OPS,
},
};
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index d72680b4..228e3fb 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -26,390 +26,16 @@
#ifndef __R8A66597_H__
#define __R8A66597_H__
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
#include <linux/clk.h>
#endif
#include <linux/usb/r8a66597.h>
-#define SYSCFG0 0x00
-#define SYSCFG1 0x02
-#define SYSSTS0 0x04
-#define SYSSTS1 0x06
-#define DVSTCTR0 0x08
-#define DVSTCTR1 0x0A
-#define TESTMODE 0x0C
-#define PINCFG 0x0E
-#define DMA0CFG 0x10
-#define DMA1CFG 0x12
-#define CFIFO 0x14
-#define D0FIFO 0x18
-#define D1FIFO 0x1C
-#define CFIFOSEL 0x20
-#define CFIFOCTR 0x22
-#define CFIFOSIE 0x24
-#define D0FIFOSEL 0x28
-#define D0FIFOCTR 0x2A
-#define D1FIFOSEL 0x2C
-#define D1FIFOCTR 0x2E
-#define INTENB0 0x30
-#define INTENB1 0x32
-#define INTENB2 0x34
-#define BRDYENB 0x36
-#define NRDYENB 0x38
-#define BEMPENB 0x3A
-#define SOFCFG 0x3C
-#define INTSTS0 0x40
-#define INTSTS1 0x42
-#define INTSTS2 0x44
-#define BRDYSTS 0x46
-#define NRDYSTS 0x48
-#define BEMPSTS 0x4A
-#define FRMNUM 0x4C
-#define UFRMNUM 0x4E
-#define USBADDR 0x50
-#define USBREQ 0x54
-#define USBVAL 0x56
-#define USBINDX 0x58
-#define USBLENG 0x5A
-#define DCPCFG 0x5C
-#define DCPMAXP 0x5E
-#define DCPCTR 0x60
-#define PIPESEL 0x64
-#define PIPECFG 0x68
-#define PIPEBUF 0x6A
-#define PIPEMAXP 0x6C
-#define PIPEPERI 0x6E
-#define PIPE1CTR 0x70
-#define PIPE2CTR 0x72
-#define PIPE3CTR 0x74
-#define PIPE4CTR 0x76
-#define PIPE5CTR 0x78
-#define PIPE6CTR 0x7A
-#define PIPE7CTR 0x7C
-#define PIPE8CTR 0x7E
-#define PIPE9CTR 0x80
-#define PIPE1TRE 0x90
-#define PIPE1TRN 0x92
-#define PIPE2TRE 0x94
-#define PIPE2TRN 0x96
-#define PIPE3TRE 0x98
-#define PIPE3TRN 0x9A
-#define PIPE4TRE 0x9C
-#define PIPE4TRN 0x9E
-#define PIPE5TRE 0xA0
-#define PIPE5TRN 0xA2
-#define DEVADD0 0xD0
-#define DEVADD1 0xD2
-#define DEVADD2 0xD4
-#define DEVADD3 0xD6
-#define DEVADD4 0xD8
-#define DEVADD5 0xDA
-#define DEVADD6 0xDC
-#define DEVADD7 0xDE
-#define DEVADD8 0xE0
-#define DEVADD9 0xE2
-#define DEVADDA 0xE4
-
-/* System Configuration Control Register */
-#define XTAL 0xC000 /* b15-14: Crystal selection */
-#define XTAL48 0x8000 /* 48MHz */
-#define XTAL24 0x4000 /* 24MHz */
-#define XTAL12 0x0000 /* 12MHz */
-#define XCKE 0x2000 /* b13: External clock enable */
-#define PLLC 0x0800 /* b11: PLL control */
-#define SCKE 0x0400 /* b10: USB clock enable */
-#define PCSDIS 0x0200 /* b9: not CS wakeup */
-#define LPSME 0x0100 /* b8: Low power sleep mode */
-#define HSE 0x0080 /* b7: Hi-speed enable */
-#define DCFM 0x0040 /* b6: Controller function select */
-#define DRPD 0x0020 /* b5: D+/- pull down control */
-#define DPRPU 0x0010 /* b4: D+ pull up control */
-#define USBE 0x0001 /* b0: USB module operation enable */
-
-/* System Configuration Status Register */
-#define OVCBIT 0x8000 /* b15-14: Over-current bit */
-#define OVCMON 0xC000 /* b15-14: Over-current monitor */
-#define SOFEA 0x0020 /* b5: SOF monitor */
-#define IDMON 0x0004 /* b3: ID-pin monitor */
-#define LNST 0x0003 /* b1-0: D+, D- line status */
-#define SE1 0x0003 /* SE1 */
-#define FS_KSTS 0x0002 /* Full-Speed K State */
-#define FS_JSTS 0x0001 /* Full-Speed J State */
-#define LS_JSTS 0x0002 /* Low-Speed J State */
-#define LS_KSTS 0x0001 /* Low-Speed K State */
-#define SE0 0x0000 /* SE0 */
-
-/* Device State Control Register */
-#define EXTLP0 0x0400 /* b10: External port */
-#define VBOUT 0x0200 /* b9: VBUS output */
-#define WKUP 0x0100 /* b8: Remote wakeup */
-#define RWUPE 0x0080 /* b7: Remote wakeup sense */
-#define USBRST 0x0040 /* b6: USB reset enable */
-#define RESUME 0x0020 /* b5: Resume enable */
-#define UACT 0x0010 /* b4: USB bus enable */
-#define RHST 0x0007 /* b1-0: Reset handshake status */
-#define HSPROC 0x0004 /* HS handshake is processing */
-#define HSMODE 0x0003 /* Hi-Speed mode */
-#define FSMODE 0x0002 /* Full-Speed mode */
-#define LSMODE 0x0001 /* Low-Speed mode */
-#define UNDECID 0x0000 /* Undecided */
-
-/* Test Mode Register */
-#define UTST 0x000F /* b3-0: Test select */
-#define H_TST_PACKET 0x000C /* HOST TEST Packet */
-#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
-#define H_TST_K 0x000A /* HOST TEST K */
-#define H_TST_J 0x0009 /* HOST TEST J */
-#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
-#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
-#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
-#define P_TST_K 0x0002 /* PERI TEST K */
-#define P_TST_J 0x0001 /* PERI TEST J */
-#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
-
-/* Data Pin Configuration Register */
-#define LDRV 0x8000 /* b15: Drive Current Adjust */
-#define VIF1 0x0000 /* VIF = 1.8V */
-#define VIF3 0x8000 /* VIF = 3.3V */
-#define INTA 0x0001 /* b1: USB INT-pin active */
-
-/* DMAx Pin Configuration Register */
-#define DREQA 0x4000 /* b14: Dreq active select */
-#define BURST 0x2000 /* b13: Burst mode */
-#define DACKA 0x0400 /* b10: Dack active select */
-#define DFORM 0x0380 /* b9-7: DMA mode select */
-#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
-#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
-#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
-#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
-#define DENDA 0x0040 /* b6: Dend active select */
-#define PKTM 0x0020 /* b5: Packet mode */
-#define DENDE 0x0010 /* b4: Dend enable */
-#define OBUS 0x0004 /* b2: OUTbus mode */
-
-/* CFIFO/DxFIFO Port Select Register */
-#define RCNT 0x8000 /* b15: Read count mode */
-#define REW 0x4000 /* b14: Buffer rewind */
-#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
-#define DREQE 0x1000 /* b12: DREQ output enable */
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define MBW 0x0800
-#else
-#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
-#endif
-#define MBW_8 0x0000 /* 8bit */
-#define MBW_16 0x0400 /* 16bit */
-#define BIGEND 0x0100 /* b8: Big endian mode */
-#define BYTE_LITTLE 0x0000 /* little dendian */
-#define BYTE_BIG 0x0100 /* big endifan */
-#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
-#define CURPIPE 0x000F /* b2-0: PIPE select */
-
-/* CFIFO/DxFIFO Port Control Register */
-#define BVAL 0x8000 /* b15: Buffer valid flag */
-#define BCLR 0x4000 /* b14: Buffer clear */
-#define FRDY 0x2000 /* b13: FIFO ready */
-#define DTLN 0x0FFF /* b11-0: FIFO received data length */
-
-/* Interrupt Enable Register 0 */
-#define VBSE 0x8000 /* b15: VBUS interrupt */
-#define RSME 0x4000 /* b14: Resume interrupt */
-#define SOFE 0x2000 /* b13: Frame update interrupt */
-#define DVSE 0x1000 /* b12: Device state transition interrupt */
-#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
-
-/* Interrupt Enable Register 1 */
-#define OVRCRE 0x8000 /* b15: Over-current interrupt */
-#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
-#define DTCHE 0x1000 /* b12: Detach sense interrupt */
-#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
-#define EOFERRE 0x0040 /* b6: EOF error interrupt */
-#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
-#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
-
-/* BRDY Interrupt Enable/Status Register */
-#define BRDY9 0x0200 /* b9: PIPE9 */
-#define BRDY8 0x0100 /* b8: PIPE8 */
-#define BRDY7 0x0080 /* b7: PIPE7 */
-#define BRDY6 0x0040 /* b6: PIPE6 */
-#define BRDY5 0x0020 /* b5: PIPE5 */
-#define BRDY4 0x0010 /* b4: PIPE4 */
-#define BRDY3 0x0008 /* b3: PIPE3 */
-#define BRDY2 0x0004 /* b2: PIPE2 */
-#define BRDY1 0x0002 /* b1: PIPE1 */
-#define BRDY0 0x0001 /* b1: PIPE0 */
-
-/* NRDY Interrupt Enable/Status Register */
-#define NRDY9 0x0200 /* b9: PIPE9 */
-#define NRDY8 0x0100 /* b8: PIPE8 */
-#define NRDY7 0x0080 /* b7: PIPE7 */
-#define NRDY6 0x0040 /* b6: PIPE6 */
-#define NRDY5 0x0020 /* b5: PIPE5 */
-#define NRDY4 0x0010 /* b4: PIPE4 */
-#define NRDY3 0x0008 /* b3: PIPE3 */
-#define NRDY2 0x0004 /* b2: PIPE2 */
-#define NRDY1 0x0002 /* b1: PIPE1 */
-#define NRDY0 0x0001 /* b1: PIPE0 */
-
-/* BEMP Interrupt Enable/Status Register */
-#define BEMP9 0x0200 /* b9: PIPE9 */
-#define BEMP8 0x0100 /* b8: PIPE8 */
-#define BEMP7 0x0080 /* b7: PIPE7 */
-#define BEMP6 0x0040 /* b6: PIPE6 */
-#define BEMP5 0x0020 /* b5: PIPE5 */
-#define BEMP4 0x0010 /* b4: PIPE4 */
-#define BEMP3 0x0008 /* b3: PIPE3 */
-#define BEMP2 0x0004 /* b2: PIPE2 */
-#define BEMP1 0x0002 /* b1: PIPE1 */
-#define BEMP0 0x0001 /* b0: PIPE0 */
-
-/* SOF Pin Configuration Register */
-#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
-#define BRDYM 0x0040 /* b6: BRDY clear timing */
-#define INTL 0x0020 /* b5: Interrupt sense select */
-#define EDGESTS 0x0010 /* b4: */
-#define SOFMODE 0x000C /* b3-2: SOF pin select */
-#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
-#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
-#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
-
-/* Interrupt Status Register 0 */
-#define VBINT 0x8000 /* b15: VBUS interrupt */
-#define RESM 0x4000 /* b14: Resume interrupt */
-#define SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define DVST 0x1000 /* b12: Device state transition interrupt */
-#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define VBSTS 0x0080 /* b7: VBUS input port */
-#define DVSQ 0x0070 /* b6-4: Device state */
-#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
-#define DS_SPD_ADDR 0x0060 /* Suspend Address */
-#define DS_SPD_DFLT 0x0050 /* Suspend Default */
-#define DS_SPD_POWR 0x0040 /* Suspend Powered */
-#define DS_SUSP 0x0040 /* Suspend */
-#define DS_CNFG 0x0030 /* Configured */
-#define DS_ADDS 0x0020 /* Address */
-#define DS_DFLT 0x0010 /* Default */
-#define DS_POWR 0x0000 /* Powered */
-#define DVSQS 0x0030 /* b5-4: Device state */
-#define VALID 0x0008 /* b3: Setup packet detected flag */
-#define CTSQ 0x0007 /* b2-0: Control transfer stage */
-#define CS_SQER 0x0006 /* Sequence error */
-#define CS_WRND 0x0005 /* Control write nodata status stage */
-#define CS_WRSS 0x0004 /* Control write status stage */
-#define CS_WRDS 0x0003 /* Control write data stage */
-#define CS_RDSS 0x0002 /* Control read status stage */
-#define CS_RDDS 0x0001 /* Control read data stage */
-#define CS_IDST 0x0000 /* Idle or setup stage */
-
-/* Interrupt Status Register 1 */
-#define OVRCR 0x8000 /* b15: Over-current interrupt */
-#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
-#define DTCH 0x1000 /* b12: Detach sense interrupt */
-#define ATTCH 0x0800 /* b11: Attach sense interrupt */
-#define EOFERR 0x0040 /* b6: EOF-error interrupt */
-#define SIGN 0x0020 /* b5: Setup ignore interrupt */
-#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
-
-/* Frame Number Register */
-#define OVRN 0x8000 /* b15: Overrun error */
-#define CRCE 0x4000 /* b14: Received data error */
-#define FRNM 0x07FF /* b10-0: Frame number */
-
-/* Micro Frame Number Register */
-#define UFRNM 0x0007 /* b2-0: Micro frame number */
-
-/* Default Control Pipe Maxpacket Size Register */
-/* Pipe Maxpacket Size Register */
-#define DEVSEL 0xF000 /* b15-14: Device address select */
-#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
-
-/* Default Control Pipe Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define SUREQ 0x4000 /* b14: Send USB request */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define SUREQCLR 0x0800 /* b11: stop setup request */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PINGE 0x0010 /* b4: ping enable */
-#define CCPL 0x0004 /* b2: Enable control transfer complete */
-#define PID 0x0003 /* b1-0: Response PID */
-#define PID_STALL11 0x0003 /* STALL */
-#define PID_STALL 0x0002 /* STALL */
-#define PID_BUF 0x0001 /* BUF */
-#define PID_NAK 0x0000 /* NAK */
-
-/* Pipe Window Select Register */
-#define PIPENM 0x0007 /* b2-0: Pipe select */
-
-/* Pipe Configuration Register */
-#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
-#define R8A66597_ISO 0xC000 /* Isochronous */
-#define R8A66597_INT 0x8000 /* Interrupt */
-#define R8A66597_BULK 0x4000 /* Bulk */
-#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
-#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
-#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
-#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
-#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
-
-/* Pipe Buffer Configuration Register */
-#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
-#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
-#define PIPE0BUF 256
-#define PIPExBUF 64
-
-/* Pipe Maxpacket Size Register */
-#define MXPS 0x07FF /* b10-0: Maxpacket size */
-
-/* Pipe Cycle Configuration Register */
-#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define IITV 0x0007 /* b2-0: Isochronous interval */
-
-/* Pipex Control Register */
-#define BSTS 0x8000 /* b15: Buffer status */
-#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define CSCLR 0x2000 /* b13: complete-split status clear */
-#define CSSTS 0x1000 /* b12: complete-split status */
-#define ATREPM 0x0400 /* b10: Auto repeat mode */
-#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define PBUSY 0x0020 /* b5: pipe busy */
-#define PID 0x0003 /* b1-0: Response PID */
-
-/* PIPExTRE */
-#define TRENB 0x0200 /* b9: Transaction counter enable */
-#define TRCLR 0x0100 /* b8: Transaction counter clear */
-
-/* PIPExTRN */
-#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
-
-/* DEVADDx */
-#define UPPHUB 0x7800
-#define HUBPORT 0x0700
-#define USBSPD 0x00C0
-#define RTPORT 0x0001
-
#define R8A66597_MAX_NUM_PIPE 10
#define R8A66597_BUF_BSIZE 8
#define R8A66597_MAX_DEVICE 10
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-#define R8A66597_MAX_ROOT_HUB 1
-#else
#define R8A66597_MAX_ROOT_HUB 2
-#endif
#define R8A66597_MAX_SAMPLING 5
#define R8A66597_RH_POLL_TIME 10
#define R8A66597_MAX_DMA_CHANNEL 2
@@ -487,7 +113,7 @@ struct r8a66597_root_hub {
struct r8a66597 {
spinlock_t lock;
unsigned long reg;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
+#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
struct r8a66597_platdata *pdata;
@@ -504,6 +130,7 @@ struct r8a66597 {
unsigned short interval_map;
unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
unsigned char dma_map;
+ unsigned int max_root_hub;
struct list_head child_device;
unsigned long child_connect_map[4];
@@ -550,21 +177,22 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long fifoaddr = r8a66597->reg + offset;
unsigned long count;
- count = len / 4;
- insl(fifoaddr, buf, count);
+ if (r8a66597->pdata->on_chip) {
+ count = len / 4;
+ insl(fifoaddr, buf, count);
- if (len & 0x00000003) {
- unsigned long tmp = inl(fifoaddr);
- memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+ if (len & 0x00000003) {
+ unsigned long tmp = inl(fifoaddr);
+ memcpy((unsigned char *)buf + count * 4, &tmp,
+ len & 0x03);
+ }
+ } else {
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
}
-#else
- len = (len + 1) / 2;
- insw(r8a66597->reg + offset, buf, len);
-#endif
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
@@ -578,33 +206,33 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
int len)
{
unsigned long fifoaddr = r8a66597->reg + offset;
-#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long count;
unsigned char *pb;
int i;
- count = len / 4;
- outsl(fifoaddr, buf, count);
+ if (r8a66597->pdata->on_chip) {
+ count = len / 4;
+ outsl(fifoaddr, buf, count);
+
+ if (len & 0x00000003) {
+ pb = (unsigned char *)buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+ outb(pb[i], fifoaddr + i);
+ else
+ outb(pb[i], fifoaddr + 3 - i);
+ }
+ }
+ } else {
+ int odd = len & 0x0001;
- if (len & 0x00000003) {
- pb = (unsigned char *)buf + count * 4;
- for (i = 0; i < (len & 0x00000003); i++) {
- if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
- outb(pb[i], fifoaddr + i);
- else
- outb(pb[i], fifoaddr + 3 - i);
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (unlikely(odd)) {
+ buf = &buf[len];
+ outb((unsigned char)*buf, fifoaddr);
}
}
-#else
- int odd = len & 0x0001;
-
- len = len / 2;
- outsw(fifoaddr, buf, len);
- if (unlikely(odd)) {
- buf = &buf[len];
- outb((unsigned char)*buf, fifoaddr);
- }
-#endif
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 90e1a8d..e75bb87 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -727,7 +727,7 @@ static const struct file_operations iowarrior_fops = {
.poll = iowarrior_poll,
};
-static char *iowarrior_nodename(struct device *dev)
+static char *iowarrior_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
}
@@ -738,7 +738,7 @@ static char *iowarrior_nodename(struct device *dev)
*/
static struct usb_class_driver iowarrior_class = {
.name = "iowarrior%d",
- .nodename = iowarrior_nodename,
+ .devnode = iowarrior_devnode,
.fops = &iowarrior_fops,
.minor_base = IOWARRIOR_MINOR_BASE,
};
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index c1e2433..97efeae 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -266,7 +266,7 @@ static const struct file_operations tower_fops = {
.llseek = tower_llseek,
};
-static char *legousbtower_nodename(struct device *dev)
+static char *legousbtower_devnode(struct device *dev, mode_t *mode)
{
return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
}
@@ -277,7 +277,7 @@ static char *legousbtower_nodename(struct device *dev)
*/
static struct usb_class_driver tower_class = {
.name = "legousbtower%d",
- .nodename = legousbtower_nodename,
+ .devnode = legousbtower_devnode,
.fops = &tower_fops,
.minor_base = LEGO_USB_TOWER_MINOR_BASE,
};
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index aec6188..5d25d3e 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -35,11 +35,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-struct ark3116_private {
- spinlock_t lock;
- u8 termios_initialized;
-};
-
static inline void ARK3116_SND(struct usb_serial *serial, int seq,
__u8 request, __u8 requesttype,
__u16 value, __u16 index)
@@ -82,22 +77,11 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
static int ark3116_attach(struct usb_serial *serial)
{
char *buf;
- struct ark3116_private *priv;
- int i;
-
- for (i = 0; i < serial->num_ports; ++i) {
- priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
- if (!priv)
- goto cleanup;
- spin_lock_init(&priv->lock);
-
- usb_set_serial_port_data(serial->port[i], priv);
- }
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
dbg("error kmalloc -> out of mem?");
- goto cleanup;
+ return -ENOMEM;
}
/* 3 */
@@ -149,13 +133,16 @@ static int ark3116_attach(struct usb_serial *serial)
kfree(buf);
return 0;
+}
-cleanup:
- for (--i; i >= 0; --i) {
- kfree(usb_get_serial_port_data(serial->port[i]));
- usb_set_serial_port_data(serial->port[i], NULL);
- }
- return -ENOMEM;
+static void ark3116_init_termios(struct tty_struct *tty)
+{
+ struct ktermios *termios = tty->termios;
+ *termios = tty_std_termios;
+ termios->c_cflag = B9600 | CS8
+ | CREAD | HUPCL | CLOCAL;
+ termios->c_ispeed = 9600;
+ termios->c_ospeed = 9600;
}
static void ark3116_set_termios(struct tty_struct *tty,
@@ -163,10 +150,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
- struct ark3116_private *priv = usb_get_serial_port_data(port);
struct ktermios *termios = tty->termios;
unsigned int cflag = termios->c_cflag;
- unsigned long flags;
int baud;
int ark3116_baud;
char *buf;
@@ -176,16 +161,6 @@ static void ark3116_set_termios(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->termios_initialized) {
- *termios = tty_std_termios;
- termios->c_cflag = B9600 | CS8
- | CREAD | HUPCL | CLOCAL;
- termios->c_ispeed = 9600;
- termios->c_ospeed = 9600;
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
cflag = termios->c_cflag;
termios->c_cflag &= ~(CMSPAR|CRTSCTS);
@@ -318,8 +293,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
return;
}
-static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
@@ -334,7 +308,7 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port,
return -ENOMEM;
}
- result = usb_serial_generic_open(tty, port, filp);
+ result = usb_serial_generic_open(tty, port);
if (result)
goto err_out;
@@ -455,6 +429,7 @@ static struct usb_serial_driver ark3116_device = {
.num_ports = 1,
.attach = ark3116_attach,
.set_termios = ark3116_set_termios,
+ .init_termios = ark3116_init_termios,
.ioctl = ark3116_ioctl,
.tiocmget = ark3116_tiocmget,
.open = ark3116_open,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 7033b03..a0467bc 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -92,7 +92,7 @@ static int debug;
static int belkin_sa_startup(struct usb_serial *serial);
static void belkin_sa_release(struct usb_serial *serial);
static int belkin_sa_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+ struct usb_serial_port *port);
static void belkin_sa_close(struct usb_serial_port *port);
static void belkin_sa_read_int_callback(struct urb *urb);
static void belkin_sa_set_termios(struct tty_struct *tty,
@@ -213,7 +213,7 @@ static void belkin_sa_release(struct usb_serial *serial)
static int belkin_sa_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+ struct usb_serial_port *port)
{
int retval = 0;
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 2830766..8c894a7 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -300,8 +300,7 @@ static void ch341_close(struct usb_serial_port *port)
/* open this device, set default parameters */
-static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
@@ -333,7 +332,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
return -EPROTO;
}
- r = usb_serial_generic_open(tty, port, filp);
+ r = usb_serial_generic_open(tty, port);
out: return r;
}
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 0e4f2e4..b22ac32 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/console.h>
+#include <linux/serial.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
@@ -63,7 +64,7 @@ static int usb_console_setup(struct console *co, char *options)
char *s;
struct usb_serial *serial;
struct usb_serial_port *port;
- int retval = 0;
+ int retval;
struct tty_struct *tty = NULL;
struct ktermios *termios = NULL, dummy;
@@ -116,13 +117,17 @@ static int usb_console_setup(struct console *co, char *options)
return -ENODEV;
}
- port = serial->port[0];
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto error_get_interface;
+
+ port = serial->port[co->index - serial->minor];
tty_port_tty_set(&port->port, NULL);
info->port = port;
++port->port.count;
- if (port->port.count == 1) {
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
if (serial->type->set_termios) {
/*
* allocate a fake tty so the driver can initialize
@@ -150,9 +155,9 @@ static int usb_console_setup(struct console *co, char *options)
/* only call the device specific open if this
* is the first time the port is opened */
if (serial->type->open)
- retval = serial->type->open(NULL, port, NULL);
+ retval = serial->type->open(NULL, port);
else
- retval = usb_serial_generic_open(NULL, port, NULL);
+ retval = usb_serial_generic_open(NULL, port);
if (retval) {
err("could not open USB console port");
@@ -168,6 +173,7 @@ static int usb_console_setup(struct console *co, char *options)
kfree(termios);
kfree(tty);
}
+ set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
/* Now that any required fake tty operations are completed restore
* the tty port count */
@@ -175,18 +181,22 @@ static int usb_console_setup(struct console *co, char *options)
/* The console is special in terms of closing the device so
* indicate this port is now acting as a system console. */
port->console = 1;
- retval = 0;
-out:
+ mutex_unlock(&serial->disc_mutex);
return retval;
-free_termios:
+
+ free_termios:
kfree(termios);
tty_port_tty_set(&port->port, NULL);
-free_tty:
+ free_tty:
kfree(tty);
-reset_open_count:
+ reset_open_count:
port->port.count = 0;
- goto out;
+ usb_autopm_put_interface(serial->interface);
+ error_get_interface:
+ usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
+ return retval;
}
static void usb_console_write(struct console *co,
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 985cbcf..4a208fe 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -33,8 +33,7 @@
/*
* Function Prototypes
*/
-static int cp210x_open(struct tty_struct *, struct usb_serial_port *,
- struct file *);
+static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
static void cp210x_cleanup(struct usb_serial_port *);
static void cp210x_close(struct usb_serial_port *);
static void cp210x_get_termios(struct tty_struct *,
@@ -368,8 +367,7 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
return baud;
}
-static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
int result;
@@ -399,12 +397,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
/* Configure the termios structure */
cp210x_get_termios(tty, port);
-
- /* Set the DTR and RTS pins low */
- cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
- : port,
- NULL, TIOCM_DTR | TIOCM_RTS, 0);
-
return 0;
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 336523f..b0f6402 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -61,7 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_disconnect(struct usb_serial *serial);
static void cyberjack_release(struct usb_serial *serial);
static int cyberjack_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+ struct usb_serial_port *port);
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
@@ -173,7 +173,7 @@ static void cyberjack_release(struct usb_serial *serial)
}
static int cyberjack_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+ struct usb_serial_port *port)
{
struct cyberjack_private *priv;
unsigned long flags;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 59adfe1..e0a8b71 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -172,8 +172,7 @@ static int cypress_earthmate_startup(struct usb_serial *serial);
static int cypress_hidcom_startup(struct usb_serial *serial);
static int cypress_ca42v2_startup(struct usb_serial *serial);
static void cypress_release(struct usb_serial *serial);
-static int cypress_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port);
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -633,8 +632,7 @@ static void cypress_release(struct usb_serial *serial)
}
-static int cypress_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
@@ -659,15 +657,7 @@ static int cypress_open(struct tty_struct *tty,
spin_unlock_irqrestore(&priv->lock, flags);
/* Set termios */
- result = cypress_write(tty, port, NULL, 0);
-
- if (result) {
- dev_err(&port->dev,
- "%s - failed setting the control lines - error %d\n",
- __func__, result);
- return result;
- } else
- dbg("%s - success setting the control lines", __func__);
+ cypress_send(port);
if (tty)
cypress_set_termios(tty, port, &priv->tmp_termios);
@@ -1005,6 +995,8 @@ static void cypress_set_termios(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
+ /* We can't clean this one up as we don't know the device type
+ early enough */
if (!priv->termios_initialized) {
if (priv->chiptype == CT_EARTHMATE) {
*(tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index f480809..ab3dd99 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -453,8 +453,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
static void digi_write_bulk_callback(struct urb *urb);
static int digi_write_room(struct tty_struct *tty);
static int digi_chars_in_buffer(struct tty_struct *tty);
-static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int digi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void digi_close(struct usb_serial_port *port);
static int digi_carrier_raised(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
@@ -1347,8 +1346,7 @@ static int digi_carrier_raised(struct usb_serial_port *port)
return 0;
}
-static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int ret;
unsigned char buf[32];
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 80cb347..33c9e9c 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -79,8 +79,7 @@ static int debug;
#define EMPEG_PRODUCT_ID 0x0001
/* function prototypes for an empeg-car player */
-static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port);
static void empeg_close(struct usb_serial_port *port);
static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf,
@@ -90,8 +89,7 @@ static int empeg_chars_in_buffer(struct tty_struct *tty);
static void empeg_throttle(struct tty_struct *tty);
static void empeg_unthrottle(struct tty_struct *tty);
static int empeg_startup(struct usb_serial *serial);
-static void empeg_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios);
+static void empeg_init_termios(struct tty_struct *tty);
static void empeg_write_bulk_callback(struct urb *urb);
static void empeg_read_bulk_callback(struct urb *urb);
@@ -123,7 +121,7 @@ static struct usb_serial_driver empeg_device = {
.throttle = empeg_throttle,
.unthrottle = empeg_unthrottle,
.attach = empeg_startup,
- .set_termios = empeg_set_termios,
+ .init_termios = empeg_init_termios,
.write = empeg_write,
.write_room = empeg_write_room,
.chars_in_buffer = empeg_chars_in_buffer,
@@ -142,17 +140,13 @@ static int bytes_out;
/******************************************************************************
* Empeg specific driver functions
******************************************************************************/
-static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int empeg_open(struct tty_struct *tty,struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
int result = 0;
dbg("%s - port %d", __func__, port->number);
- /* Force default termio settings */
- empeg_set_termios(tty, port, NULL) ;
-
bytes_in = 0;
bytes_out = 0;
@@ -425,11 +419,9 @@ static int empeg_startup(struct usb_serial *serial)
}
-static void empeg_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
+static void empeg_init_termios(struct tty_struct *tty)
{
struct ktermios *termios = tty->termios;
- dbg("%s - port %d", __func__, port->number);
/*
* The empeg-car player wants these particular tty settings.
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 8fec5d4..76a17f9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -747,8 +747,7 @@ static int ftdi_sio_probe(struct usb_serial *serial,
const struct usb_device_id *id);
static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
-static int ftdi_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
@@ -1680,8 +1679,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
return 0;
}
-static int ftdi_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
{ /* ftdi_open */
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 8839f1c..20432d3 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -933,8 +933,7 @@ static int garmin_init_session(struct usb_serial_port *port)
-static int garmin_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
{
unsigned long flags;
int status = 0;
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index ce57f6a..d9398e9 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -114,8 +114,7 @@ void usb_serial_generic_deregister(void)
#endif
}
-int usb_serial_generic_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
int result = 0;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 0191693..dc0f832 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -205,8 +205,7 @@ static void edge_bulk_out_data_callback(struct urb *urb);
static void edge_bulk_out_cmd_callback(struct urb *urb);
/* function prototypes for the usbserial callbacks */
-static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int edge_open(struct tty_struct *tty, struct usb_serial_port *port);
static void edge_close(struct usb_serial_port *port);
static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -852,8 +851,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb)
* If successful, we return 0
* Otherwise we return a negative error number.
*****************************************************************************/
-static int edge_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct usb_serial *serial;
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index e8bc42f..d4cc0f7 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1831,8 +1831,7 @@ static void edge_bulk_out_callback(struct urb *urb)
tty_kref_put(tty);
}
-static int edge_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct edgeport_serial *edge_serial;
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 2545d45..24fcc64 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -75,7 +75,7 @@ static int initial_wait;
/* Function prototypes for an ipaq */
static int ipaq_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+ struct usb_serial_port *port);
static void ipaq_close(struct usb_serial_port *port);
static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
@@ -587,7 +587,7 @@ static int bytes_in;
static int bytes_out;
static int ipaq_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+ struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct ipaq_private *priv;
@@ -628,11 +628,6 @@ static int ipaq_open(struct tty_struct *tty,
priv->free_len += PACKET_SIZE;
}
- if (tty) {
- /* FIXME: These two are bogus */
- tty->raw = 1;
- tty->real_raw = 1;
- }
/*
* Lose the small buffers usbserial provides. Make larger ones.
*/
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 29ad038..727d323 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -193,8 +193,7 @@ static void ipw_read_bulk_callback(struct urb *urb)
return;
}
-static int ipw_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_device *dev = port->serial->dev;
u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT;
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 66009b6..95d8d26b 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -86,8 +86,7 @@ static int buffer_size;
static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
-static int ir_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filep);
+static int ir_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ir_close(struct usb_serial_port *port);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -296,8 +295,7 @@ static int ir_startup(struct usb_serial *serial)
return 0;
}
-static int ir_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
{
char *buffer;
int result = 0;
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 96873a7..6138c1c 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -71,7 +71,6 @@ struct iuu_private {
spinlock_t lock; /* store irq state */
wait_queue_head_t delta_msr_wait;
u8 line_status;
- u8 termios_initialized;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
u8 reset; /* if 1 reset is needed */
int poll; /* number of poll */
@@ -1018,14 +1017,24 @@ static void iuu_close(struct usb_serial_port *port)
}
}
-static int iuu_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static void iuu_init_termios(struct tty_struct *tty)
+{
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ | TIOCM_CTS | CSTOPB | PARENB;
+ tty->termios->c_ispeed = 9600;
+ tty->termios->c_ospeed = 9600;
+ tty->termios->c_lflag = 0;
+ tty->termios->c_oflag = 0;
+ tty->termios->c_iflag = 0;
+}
+
+static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
u8 *buf;
int result;
u32 actual;
- unsigned long flags;
struct iuu_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __func__, port->number);
@@ -1064,21 +1073,7 @@ static int iuu_open(struct tty_struct *tty,
port->bulk_in_buffer, 512,
NULL, NULL);
- /* set the termios structure */
- spin_lock_irqsave(&priv->lock, flags);
- if (tty && !priv->termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
- | TIOCM_CTS | CSTOPB | PARENB;
- tty->termios->c_ispeed = 9600;
- tty->termios->c_ospeed = 9600;
- tty->termios->c_lflag = 0;
- tty->termios->c_oflag = 0;
- tty->termios->c_iflag = 0;
- priv->termios_initialized = 1;
- priv->poll = 0;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
+ priv->poll = 0;
/* initialize writebuf */
#define FISH(a, b, c, d) do { \
@@ -1201,6 +1196,7 @@ static struct usb_serial_driver iuu_device = {
.tiocmget = iuu_tiocmget,
.tiocmset = iuu_tiocmset,
.set_termios = iuu_set_termios,
+ .init_termios = iuu_init_termios,
.attach = iuu_startup,
.release = iuu_release,
};
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 2594b87..f8c4b07 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1209,8 +1209,7 @@ static int keyspan_write_room(struct tty_struct *tty)
}
-static int keyspan_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct keyspan_port_private *p_priv;
struct keyspan_serial_private *s_priv;
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 3107ed1..30771e5 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -36,8 +36,7 @@
/* Function prototypes for Keyspan serial converter */
static int keyspan_open (struct tty_struct *tty,
- struct usb_serial_port *port,
- struct file *filp);
+ struct usb_serial_port *port);
static void keyspan_close (struct usb_serial_port *port);
static void keyspan_dtr_rts (struct usb_serial_port *port, int on);
static int keyspan_startup (struct usb_serial *serial);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index d0b12e4..257c16c 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -681,7 +681,7 @@ static int keyspan_pda_carrier_raised(struct usb_serial_port *port)
static int keyspan_pda_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+ struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
unsigned char room;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 0f44bb8..a616731 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -75,8 +75,7 @@ static int debug;
static int klsi_105_startup(struct usb_serial *serial);
static void klsi_105_disconnect(struct usb_serial *serial);
static void klsi_105_release(struct usb_serial *serial);
-static int klsi_105_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
static void klsi_105_close(struct usb_serial_port *port);
static int klsi_105_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
@@ -358,8 +357,7 @@ static void klsi_105_release(struct usb_serial *serial)
}
} /* klsi_105_release */
-static int klsi_105_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
int retval = 0;
@@ -371,10 +369,6 @@ static int klsi_105_open(struct tty_struct *tty,
dbg("%s port %d", __func__, port->number);
- /* force low_latency on so that our tty_push actually forces
- * the data through
- * tty->low_latency = 1; */
-
/* Do a defined restart:
* Set up sane default baud rate and send the 'READ_ON'
* vendor command.
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 6db0e56..45ea694 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -70,8 +70,7 @@ static int debug;
/* Function prototypes */
static int kobil_startup(struct usb_serial *serial);
static void kobil_release(struct usb_serial *serial);
-static int kobil_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port);
static void kobil_close(struct usb_serial_port *port);
static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -85,7 +84,7 @@ static void kobil_read_int_callback(struct urb *urb);
static void kobil_write_callback(struct urb *purb);
static void kobil_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
-
+static void kobil_init_termios(struct tty_struct *tty);
static struct usb_device_id id_table [] = {
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
@@ -120,6 +119,7 @@ static struct usb_serial_driver kobil_device = {
.release = kobil_release,
.ioctl = kobil_ioctl,
.set_termios = kobil_set_termios,
+ .init_termios = kobil_init_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@@ -210,9 +210,17 @@ static void kobil_release(struct usb_serial *serial)
kfree(usb_get_serial_port_data(serial->port[i]));
}
+static void kobil_init_termios(struct tty_struct *tty)
+{
+ /* Default to echo off and other sane device settings */
+ tty->termios->c_lflag = 0;
+ tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+ tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+ /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
+ tty->termios->c_oflag &= ~ONLCR;
+}
-static int kobil_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
struct kobil_private *priv;
@@ -226,16 +234,6 @@ static int kobil_open(struct tty_struct *tty,
/* someone sets the dev to 0 if the close method has been called */
port->interrupt_in_urb->dev = port->serial->dev;
- if (tty) {
-
- /* Default to echo off and other sane device settings */
- tty->termios->c_lflag = 0;
- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN |
- XCASE);
- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
- /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
- tty->termios->c_oflag &= ~ONLCR;
- }
/* allocate memory for transfer buffer */
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (!transfer_buffer)
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index d8825e1..ad4998b 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -93,8 +93,7 @@ static int debug;
*/
static int mct_u232_startup(struct usb_serial *serial);
static void mct_u232_release(struct usb_serial *serial);
-static int mct_u232_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port);
static void mct_u232_close(struct usb_serial_port *port);
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
static void mct_u232_read_int_callback(struct urb *urb);
@@ -421,8 +420,7 @@ static void mct_u232_release(struct usb_serial *serial)
}
} /* mct_u232_release */
-static int mct_u232_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
@@ -568,10 +566,13 @@ static void mct_u232_read_int_callback(struct urb *urb)
* Work-a-round: handle the 'usual' bulk-in pipe here
*/
if (urb->transfer_buffer_length > 2) {
- tty = tty_port_tty_get(&port->port);
if (urb->actual_length) {
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ tty_insert_flip_string(tty, data,
+ urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
tty_kref_put(tty);
}
goto exit;
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index ccd4dd3..763e32a 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -85,7 +85,7 @@ static int debug;
#define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715
-static struct usb_device_id moschip_port_id_table [] = {
+static struct usb_device_id moschip_port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
{ } /* terminating entry */
};
@@ -319,8 +319,7 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
return status;
}
-static int mos7720_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial;
struct usb_serial_port *port0;
@@ -378,10 +377,14 @@ static int mos7720_open(struct tty_struct *tty,
/* Initialize MCS7720 -- Write Init values to corresponding Registers
*
* Register Index
+ * 0 : THR/RHR
* 1 : IER
* 2 : FCR
* 3 : LCR
* 4 : MCR
+ * 5 : LSR
+ * 6 : MSR
+ * 7 : SPR
*
* 0x08 : SP1/2 Control Reg
*/
@@ -1250,20 +1253,88 @@ static void mos7720_set_termios(struct tty_struct *tty,
static int get_lsr_info(struct tty_struct *tty,
struct moschip_port *mos7720_port, unsigned int __user *value)
{
- int count;
+ struct usb_serial_port *port = tty->driver_data;
unsigned int result = 0;
+ unsigned char data = 0;
+ int port_number = port->number - port->serial->minor;
+ int count;
count = mos7720_chars_in_buffer(tty);
if (count == 0) {
- dbg("%s -- Empty", __func__);
- result = TIOCSER_TEMT;
+ send_mos_cmd(port->serial, MOS_READ, port_number,
+ UART_LSR, &data);
+ if ((data & (UART_LSR_TEMT | UART_LSR_THRE))
+ == (UART_LSR_TEMT | UART_LSR_THRE)) {
+ dbg("%s -- Empty", __func__);
+ result = TIOCSER_TEMT;
+ }
}
-
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return 0;
}
+static int mos7720_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+ unsigned int result = 0;
+ unsigned int mcr ;
+ unsigned int msr ;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ mcr = mos7720_port->shadowMCR;
+ msr = mos7720_port->shadowMSR;
+
+ result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
+ | ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
+ | ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
+ | ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) /* 0x040 */
+ | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
+ | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
+
+ dbg("%s -- %x", __func__, result);
+
+ return result;
+}
+
+static int mos7720_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+ unsigned int mcr ;
+ unsigned char lmcr;
+
+ dbg("%s - port %d", __func__, port->number);
+ dbg("he was at tiocmget");
+
+ mcr = mos7720_port->shadowMCR;
+
+ if (set & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (set & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (set & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ if (clear & TIOCM_RTS)
+ mcr &= ~UART_MCR_RTS;
+ if (clear & TIOCM_DTR)
+ mcr &= ~UART_MCR_DTR;
+ if (clear & TIOCM_LOOP)
+ mcr &= ~UART_MCR_LOOP;
+
+ mos7720_port->shadowMCR = mcr;
+ lmcr = mos7720_port->shadowMCR;
+
+ send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor, UART_MCR, &lmcr);
+
+ return 0;
+}
+
static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
unsigned int __user *value)
{
@@ -1301,14 +1372,6 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
mcr &= ~UART_MCR_LOOP;
break;
- case TIOCMSET:
- /* turn off the RTS and DTR and LOOPBACK
- * and then only turn on what was asked to */
- mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
- mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
- mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
- mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
- break;
}
mos7720_port->shadowMCR = mcr;
@@ -1320,28 +1383,6 @@ static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
return 0;
}
-static int get_modem_info(struct moschip_port *mos7720_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
- unsigned int msr = mos7720_port->shadowMSR;
- unsigned int mcr = mos7720_port->shadowMCR;
-
- result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */
- | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */
- | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */
- | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */
- | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */
- | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
-
-
- dbg("%s -- %x", __func__, result);
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
static int get_serial_info(struct moschip_port *mos7720_port,
struct serial_struct __user *retinfo)
{
@@ -1392,17 +1433,11 @@ static int mos7720_ioctl(struct tty_struct *tty, struct file *file,
/* FIXME: These should be using the mode methods */
case TIOCMBIS:
case TIOCMBIC:
- case TIOCMSET:
dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET",
__func__, port->number);
return set_modem_info(mos7720_port, cmd,
(unsigned int __user *)arg);
- case TIOCMGET:
- dbg("%s (%d) TIOCMGET", __func__, port->number);
- return get_modem_info(mos7720_port,
- (unsigned int __user *)arg);
-
case TIOCGSERIAL:
dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
return get_serial_info(mos7720_port,
@@ -1557,6 +1592,8 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.attach = mos7720_startup,
.release = mos7720_release,
.ioctl = mos7720_ioctl,
+ .tiocmget = mos7720_tiocmget,
+ .tiocmset = mos7720_tiocmset,
.set_termios = mos7720_set_termios,
.write = mos7720_write,
.write_room = mos7720_write_room,
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 270009a..f11abf5 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -824,8 +824,7 @@ static int mos7840_serial_probe(struct usb_serial *serial,
* Otherwise we return a negative error number.
*****************************************************************************/
-static int mos7840_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int response;
int j;
@@ -2134,106 +2133,6 @@ static int mos7840_get_lsr_info(struct tty_struct *tty,
}
/*****************************************************************************
- * mos7840_set_modem_info
- * function to set modem info
- *****************************************************************************/
-
-/* FIXME: Should be using the model control hooks */
-
-static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
- unsigned int cmd, unsigned int __user *value)
-{
- unsigned int mcr;
- unsigned int arg;
- __u16 Data;
- int status;
- struct usb_serial_port *port;
-
- if (mos7840_port == NULL)
- return -1;
-
- port = (struct usb_serial_port *)mos7840_port->port;
- if (mos7840_port_paranoia_check(port, __func__)) {
- dbg("%s", "Invalid port");
- return -1;
- }
-
- mcr = mos7840_port->shadowMCR;
-
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS)
- mcr |= MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr |= MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr |= MCR_LOOPBACK;
- break;
-
- case TIOCMBIC:
- if (arg & TIOCM_RTS)
- mcr &= ~MCR_RTS;
- if (arg & TIOCM_DTR)
- mcr &= ~MCR_RTS;
- if (arg & TIOCM_LOOP)
- mcr &= ~MCR_LOOPBACK;
- break;
-
- case TIOCMSET:
- /* turn off the RTS and DTR and LOOPBACK
- * and then only turn on what was asked to */
- mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
- mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
- mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
- mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
- break;
- }
-
- lock_kernel();
- mos7840_port->shadowMCR = mcr;
-
- Data = mos7840_port->shadowMCR;
- status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
- unlock_kernel();
- if (status < 0) {
- dbg("setting MODEM_CONTROL_REGISTER Failed");
- return -1;
- }
-
- return 0;
-}
-
-/*****************************************************************************
- * mos7840_get_modem_info
- * function to get modem info
- *****************************************************************************/
-
-static int mos7840_get_modem_info(struct moschip_port *mos7840_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
- __u16 msr;
- unsigned int mcr = mos7840_port->shadowMCR;
- mos7840_get_uart_reg(mos7840_port->port,
- MODEM_STATUS_REGISTER, &msr);
- result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
- |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
- |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
- |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */
- |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
- |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
-
- dbg("%s -- %x", __func__, result);
-
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-/*****************************************************************************
* mos7840_get_serial_info
* function to get information about serial port
*****************************************************************************/
@@ -2281,7 +2180,6 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file,
struct async_icount cnow;
struct async_icount cprev;
struct serial_icounter_struct icount;
- int mosret = 0;
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
@@ -2303,20 +2201,6 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file,
return mos7840_get_lsr_info(tty, argp);
return 0;
- /* FIXME: use the modem hooks and remove this */
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __func__,
- port->number);
- mosret =
- mos7840_set_modem_info(mos7840_port, cmd, argp);
- return mosret;
-
- case TIOCMGET:
- dbg("%s (%d) TIOCMGET", __func__, port->number);
- return mos7840_get_modem_info(mos7840_port, argp);
-
case TIOCGSERIAL:
dbg("%s (%d) TIOCGSERIAL", __func__, port->number);
return mos7840_get_serial_info(mos7840_port, argp);
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index f5f3751a8..5ceaa4c6 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -80,8 +80,7 @@ exit:
__func__, result);
}
-static int navman_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int navman_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 56857dd..0622650 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -64,8 +64,7 @@ static int debug;
#define BT_IGNITIONPRO_ID 0x2000
/* function prototypes */
-static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port);
static void omninet_close(struct usb_serial_port *port);
static void omninet_read_bulk_callback(struct urb *urb);
static void omninet_write_bulk_callback(struct urb *urb);
@@ -163,8 +162,7 @@ static int omninet_attach(struct usb_serial *serial)
return 0;
}
-static int omninet_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct usb_serial_port *wport;
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 336bba7..1085a57 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -144,8 +144,7 @@ exit:
spin_unlock(&priv->lock);
}
-static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index c784ddb..fe47051 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -45,8 +45,7 @@
/* Function prototypes */
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id);
-static int option_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int option_open(struct tty_struct *tty, struct usb_serial_port *port);
static void option_close(struct usb_serial_port *port);
static void option_dtr_rts(struct usb_serial_port *port, int on);
@@ -961,8 +960,7 @@ static int option_chars_in_buffer(struct tty_struct *tty)
return data_len;
}
-static int option_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int option_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct option_port_private *portdata;
int i, err;
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 3cece27..0f4a70ce 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -141,11 +141,11 @@ struct oti6858_control_pkt {
&& ((a)->frame_fmt == (priv)->pending_setup.frame_fmt))
/* function prototypes */
-static int oti6858_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port);
static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
+static void oti6858_init_termios(struct tty_struct *tty);
static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
static void oti6858_read_int_callback(struct urb *urb);
@@ -186,6 +186,7 @@ static struct usb_serial_driver oti6858_device = {
.write = oti6858_write,
.ioctl = oti6858_ioctl,
.set_termios = oti6858_set_termios,
+ .init_termios = oti6858_init_termios,
.tiocmget = oti6858_tiocmget,
.tiocmset = oti6858_tiocmset,
.read_bulk_callback = oti6858_read_bulk_callback,
@@ -206,7 +207,6 @@ struct oti6858_private {
struct {
u8 read_urb_in_use;
u8 write_urb_in_use;
- u8 termios_initialized;
} flags;
struct delayed_work delayed_write_work;
@@ -447,6 +447,14 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
return chars;
}
+static void oti6858_init_termios(struct tty_struct *tty)
+{
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios->c_ispeed = 38400;
+ tty->termios->c_ospeed = 38400;
+}
+
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
@@ -464,16 +472,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
return;
}
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->flags.termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 38400;
- tty->termios->c_ospeed = 38400;
- priv->flags.termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
cflag = tty->termios->c_cflag;
spin_lock_irqsave(&priv->lock, flags);
@@ -566,8 +564,7 @@ static void oti6858_set_termios(struct tty_struct *tty,
spin_unlock_irqrestore(&priv->lock, flags);
}
-static int oti6858_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct oti6858_private *priv = usb_get_serial_port_data(port);
struct ktermios tmp_termios;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3e86815..a63ea99 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -691,8 +691,7 @@ static void pl2303_close(struct usb_serial_port *port)
}
-static int pl2303_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
@@ -714,8 +713,6 @@ static int pl2303_open(struct tty_struct *tty,
if (tty)
pl2303_set_termios(tty, port, &tmp_termios);
- /* FIXME: need to assert RTS and DTR if CRTSCTS off */
-
dbg("%s - submitting read urb", __func__);
port->read_urb->dev = serial->dev;
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index f48d05e..55391bb 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -734,8 +734,7 @@ static void sierra_close(struct usb_serial_port *port)
}
}
-static int sierra_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct sierra_port_private *portdata;
struct usb_serial *serial = port->serial;
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 3c249d8..61e7c40 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -299,7 +299,6 @@ struct spcp8x5_private {
wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
- u8 termios_initialized;
};
/* desc : when device plug in,this function would be called.
@@ -498,6 +497,15 @@ static void spcp8x5_close(struct usb_serial_port *port)
dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
}
+static void spcp8x5_init_termios(struct tty_struct *tty)
+{
+ /* for the 1st time call this function */
+ *(tty->termios) = tty_std_termios;
+ tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->termios->c_ispeed = 115200;
+ tty->termios->c_ospeed = 115200;
+}
+
/* set the serial param for transfer. we should check if we really need to
* transfer. if we set flow control we should do this too. */
static void spcp8x5_set_termios(struct tty_struct *tty,
@@ -514,16 +522,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
int i;
u8 control;
- /* for the 1st time call this function */
- spin_lock_irqsave(&priv->lock, flags);
- if (!priv->termios_initialized) {
- *(tty->termios) = tty_std_termios;
- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
- tty->termios->c_ispeed = 115200;
- tty->termios->c_ospeed = 115200;
- priv->termios_initialized = 1;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
/* check that they really want us to change something */
if (!tty_termios_hw_change(tty->termios, old_termios))
@@ -623,8 +621,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
/* open the serial port. do some usb system call. set termios and get the line
* status of the device. then submit the read urb */
-static int spcp8x5_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
@@ -658,8 +655,6 @@ static int spcp8x5_open(struct tty_struct *tty,
priv->line_status = status & 0xf0 ;
spin_unlock_irqrestore(&priv->lock, flags);
- /* FIXME: need to assert RTS and DTR if CRTSCTS off */
-
dbg("%s - submitting read urb", __func__);
port->read_urb->dev = serial->dev;
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -1011,6 +1006,7 @@ static struct usb_serial_driver spcp8x5_device = {
.carrier_raised = spcp8x5_carrier_raised,
.write = spcp8x5_write,
.set_termios = spcp8x5_set_termios,
+ .init_termios = spcp8x5_init_termios,
.ioctl = spcp8x5_ioctl,
.tiocmget = spcp8x5_tiocmget,
.tiocmset = spcp8x5_tiocmset,
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 6157fac..cb7e95f 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -124,8 +124,7 @@ exit:
spin_unlock(&priv->lock);
}
-static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct symbol_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 3bc609f..1e9dc88 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -98,8 +98,7 @@ struct ti_device {
static int ti_startup(struct usb_serial *serial);
static void ti_release(struct usb_serial *serial);
-static int ti_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *file);
+static int ti_open(struct tty_struct *tty, struct usb_serial_port *port);
static void ti_close(struct usb_serial_port *port);
static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
@@ -492,8 +491,7 @@ static void ti_release(struct usb_serial *serial)
}
-static int ti_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *file)
+static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct ti_port *tport = usb_get_serial_port_data(port);
struct ti_device *tdev;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 99188c9..9d7ca48 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -43,8 +43,6 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
-static void port_free(struct usb_serial_port *port);
-
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
@@ -68,6 +66,11 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
static DEFINE_MUTEX(table_lock);
static LIST_HEAD(usb_serial_driver_list);
+/*
+ * Look up the serial structure. If it is found and it hasn't been
+ * disconnected, return with its disc_mutex held and its refcount
+ * incremented. Otherwise return NULL.
+ */
struct usb_serial *usb_serial_get_by_index(unsigned index)
{
struct usb_serial *serial;
@@ -75,8 +78,15 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
mutex_lock(&table_lock);
serial = serial_table[index];
- if (serial)
- kref_get(&serial->kref);
+ if (serial) {
+ mutex_lock(&serial->disc_mutex);
+ if (serial->disconnected) {
+ mutex_unlock(&serial->disc_mutex);
+ serial = NULL;
+ } else {
+ kref_get(&serial->kref);
+ }
+ }
mutex_unlock(&table_lock);
return serial;
}
@@ -125,8 +135,10 @@ static void return_serial(struct usb_serial *serial)
dbg("%s", __func__);
+ mutex_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i)
serial_table[serial->minor + i] = NULL;
+ mutex_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -145,161 +157,157 @@ static void destroy_serial(struct kref *kref)
serial->type->release(serial);
- for (i = 0; i < serial->num_ports; ++i) {
+ /* Now that nothing is using the ports, they can be freed */
+ for (i = 0; i < serial->num_port_pointers; ++i) {
port = serial->port[i];
- if (port)
+ if (port) {
+ port->serial = NULL;
put_device(&port->dev);
- }
-
- /* If this is a "fake" port, we have to clean it up here, as it will
- * not get cleaned up in port_release() as it was never registered with
- * the driver core */
- if (serial->num_ports < serial->num_port_pointers) {
- for (i = serial->num_ports;
- i < serial->num_port_pointers; ++i) {
- port = serial->port[i];
- if (port)
- port_free(port);
}
}
usb_put_dev(serial->dev);
-
- /* free up any memory that we allocated */
kfree(serial);
}
void usb_serial_put(struct usb_serial *serial)
{
- mutex_lock(&table_lock);
kref_put(&serial->kref, destroy_serial);
- mutex_unlock(&table_lock);
}
/*****************************************************************************
* Driver tty interface functions
*****************************************************************************/
-static int serial_open (struct tty_struct *tty, struct file *filp)
+
+/**
+ * serial_install - install tty
+ * @driver: the driver (USB in our case)
+ * @tty: the tty being created
+ *
+ * Create the termios objects for this tty. We use the default
+ * USB serial settings but permit them to be overridden by
+ * serial->type->init_termios.
+ *
+ * This is the first place a new tty gets used. Hence this is where we
+ * acquire references to the usb_serial structure and the driver module,
+ * where we store a pointer to the port, and where we do an autoresume.
+ * All these actions are reversed in serial_release().
+ */
+static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
{
+ int idx = tty->index;
struct usb_serial *serial;
struct usb_serial_port *port;
- unsigned int portNumber;
- int retval = 0;
- int first = 0;
+ int retval = -ENODEV;
dbg("%s", __func__);
- /* get the serial object associated with this tty pointer */
- serial = usb_serial_get_by_index(tty->index);
- if (!serial) {
- tty->driver_data = NULL;
- return -ENODEV;
- }
+ serial = usb_serial_get_by_index(idx);
+ if (!serial)
+ return retval;
- mutex_lock(&serial->disc_mutex);
- portNumber = tty->index - serial->minor;
- port = serial->port[portNumber];
- if (!port || serial->disconnected)
- retval = -ENODEV;
- else
- get_device(&port->dev);
- /*
- * Note: Our locking order requirement does not allow port->mutex
- * to be acquired while serial->disc_mutex is held.
- */
- mutex_unlock(&serial->disc_mutex);
+ port = serial->port[idx - serial->minor];
+ if (!port)
+ goto error_no_port;
+ if (!try_module_get(serial->type->driver.owner))
+ goto error_module_get;
+
+ /* perform the standard setup */
+ retval = tty_init_termios(tty);
if (retval)
- goto bailout_serial_put;
+ goto error_init_termios;
- if (mutex_lock_interruptible(&port->mutex)) {
- retval = -ERESTARTSYS;
- goto bailout_port_put;
- }
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto error_get_interface;
+
+ mutex_unlock(&serial->disc_mutex);
- ++port->port.count;
+ /* allow the driver to update the settings */
+ if (serial->type->init_termios)
+ serial->type->init_termios(tty);
- /* set up our port structure making the tty driver
- * remember our port object, and us it */
tty->driver_data = port;
- tty_port_tty_set(&port->port, tty);
- /* If the console is attached, the device is already open */
- if (port->port.count == 1 && !port->console) {
- first = 1;
- /* lock this module before we call it
- * this may fail, which means we must bail out,
- * safe because we are called with BKL held */
- if (!try_module_get(serial->type->driver.owner)) {
- retval = -ENODEV;
- goto bailout_mutex_unlock;
- }
+ /* Final install (we use the default method) */
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+ return retval;
+ error_get_interface:
+ error_init_termios:
+ module_put(serial->type->driver.owner);
+ error_module_get:
+ error_no_port:
+ usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
+ return retval;
+}
+
+static int serial_open(struct tty_struct *tty, struct file *filp)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ int retval;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irq(&port->port.lock);
+ if (!tty_hung_up_p(filp))
+ ++port->port.count;
+ spin_unlock_irq(&port->port.lock);
+ tty_port_tty_set(&port->port, tty);
+
+ /* Do the device-specific open only if the hardware isn't
+ * already initialized.
+ */
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
+ if (mutex_lock_interruptible(&port->mutex))
+ return -ERESTARTSYS;
mutex_lock(&serial->disc_mutex);
if (serial->disconnected)
retval = -ENODEV;
else
- retval = usb_autopm_get_interface(serial->interface);
- if (retval)
- goto bailout_module_put;
-
- /* only call the device specific open if this
- * is the first time the port is opened */
- retval = serial->type->open(tty, port, filp);
- if (retval)
- goto bailout_interface_put;
+ retval = port->serial->type->open(tty, port);
mutex_unlock(&serial->disc_mutex);
+ mutex_unlock(&port->mutex);
+ if (retval)
+ return retval;
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
}
- mutex_unlock(&port->mutex);
+
/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
- if (retval == 0) {
- if (!first)
- usb_serial_put(serial);
- return 0;
- }
- mutex_lock(&port->mutex);
- if (first == 0)
- goto bailout_mutex_unlock;
- /* Undo the initial port actions */
- mutex_lock(&serial->disc_mutex);
-bailout_interface_put:
- usb_autopm_put_interface(serial->interface);
-bailout_module_put:
- mutex_unlock(&serial->disc_mutex);
- module_put(serial->type->driver.owner);
-bailout_mutex_unlock:
- port->port.count = 0;
- tty->driver_data = NULL;
- tty_port_tty_set(&port->port, NULL);
- mutex_unlock(&port->mutex);
-bailout_port_put:
- put_device(&port->dev);
-bailout_serial_put:
- usb_serial_put(serial);
return retval;
}
/**
- * serial_do_down - shut down hardware
- * @port: port to shut down
- *
- * Shut down a USB port unless it is the console. We never shut down the
- * console hardware as it will always be in use.
+ * serial_down - shut down hardware
+ * @port: port to shut down
*
- * Don't free any resources at this point
+ * Shut down a USB serial port unless it is the console. We never
+ * shut down the console hardware as it will always be in use.
*/
-static void serial_do_down(struct usb_serial_port *port)
+static void serial_down(struct usb_serial_port *port)
{
struct usb_serial_driver *drv = port->serial->type;
struct usb_serial *serial;
struct module *owner;
- /* The console is magical, do not hang up the console hardware
- or there will be tears */
+ /*
+ * The console is magical. Do not hang up the console hardware
+ * or there will be tears.
+ */
if (port->console)
return;
+ /* Don't call the close method if the hardware hasn't been
+ * initialized.
+ */
+ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ return;
+
mutex_lock(&port->mutex);
serial = port->serial;
owner = serial->type->driver.owner;
@@ -310,79 +318,69 @@ static void serial_do_down(struct usb_serial_port *port)
mutex_unlock(&port->mutex);
}
-/**
- * serial_do_free - free resources post close/hangup
- * @port: port to free up
- *
- * Do the resource freeing and refcount dropping for the port. We must
- * be careful about ordering and we must avoid freeing up the console.
- */
-
-static void serial_do_free(struct usb_serial_port *port)
+static void serial_hangup(struct tty_struct *tty)
{
- struct usb_serial *serial;
- struct module *owner;
+ struct usb_serial_port *port = tty->driver_data;
- /* The console is magical, do not hang up the console hardware
- or there will be tears */
- if (port->console)
- return;
+ dbg("%s - port %d", __func__, port->number);
- serial = port->serial;
- owner = serial->type->driver.owner;
- put_device(&port->dev);
- /* Mustn't dereference port any more */
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- usb_autopm_put_interface(serial->interface);
- mutex_unlock(&serial->disc_mutex);
- usb_serial_put(serial);
- /* Mustn't dereference serial any more */
- module_put(owner);
+ serial_down(port);
+ tty_port_hangup(&port->port);
}
static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- /* FIXME:
- This leaves a very narrow race. Really we should do the
- serial_do_free() on tty->shutdown(), but tty->shutdown can
- be called from IRQ context and serial_do_free can sleep.
-
- The right fix is probably to make the tty free (which is rare)
- and thus tty->shutdown() occur via a work queue and simplify all
- the drivers that use it.
- */
- if (tty_hung_up_p(filp)) {
- /* serial_hangup already called serial_down at this point.
- Another user may have already reopened the port but
- serial_do_free is refcounted */
- serial_do_free(port);
+ if (tty_hung_up_p(filp))
return;
- }
-
if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
-
- serial_do_down(port);
+ serial_down(port);
tty_port_close_end(&port->port, tty);
tty_port_tty_set(&port->port, NULL);
- serial_do_free(port);
}
-static void serial_hangup(struct tty_struct *tty)
+/**
+ * serial_release - free resources post close/hangup
+ * @port: port to free up
+ *
+ * Do the resource freeing and refcount dropping for the port.
+ * Avoid freeing the console.
+ *
+ * Called when the last tty kref is dropped.
+ */
+static void serial_release(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- serial_do_down(port);
- tty_port_hangup(&port->port);
- /* We must not free port yet - the USB serial layer depends on it's
- continued existence */
+ struct usb_serial *serial;
+ struct module *owner;
+
+ /* The console is magical. Do not hang up the console hardware
+ * or there will be tears.
+ */
+ if (port->console)
+ return;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ /* Standard shutdown processing */
+ tty_shutdown(tty);
+
+ tty->driver_data = NULL;
+
+ serial = port->serial;
+ owner = serial->type->driver.owner;
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ usb_autopm_put_interface(serial->interface);
+ mutex_unlock(&serial->disc_mutex);
+
+ usb_serial_put(serial);
+ module_put(owner);
}
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@@ -527,6 +525,7 @@ static int serial_proc_show(struct seq_file *m, void *v)
seq_putc(m, '\n');
usb_serial_put(serial);
+ mutex_unlock(&serial->disc_mutex);
}
return 0;
}
@@ -596,14 +595,6 @@ static void usb_serial_port_work(struct work_struct *work)
tty_kref_put(tty);
}
-static void port_release(struct device *dev)
-{
- struct usb_serial_port *port = to_usb_serial_port(dev);
-
- dbg ("%s - %s", __func__, dev_name(dev));
- port_free(port);
-}
-
static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
@@ -623,8 +614,12 @@ static void kill_traffic(struct usb_serial_port *port)
usb_kill_urb(port->interrupt_out_urb);
}
-static void port_free(struct usb_serial_port *port)
+static void port_release(struct device *dev)
{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+
+ dbg ("%s - %s", __func__, dev_name(dev));
+
/*
* Stop all the traffic before cancelling the work, so that
* nobody will restart it by calling usb_serial_port_softint.
@@ -935,6 +930,11 @@ int usb_serial_probe(struct usb_interface *interface,
mutex_init(&port->mutex);
INIT_WORK(&port->work, usb_serial_port_work);
serial->port[i] = port;
+ port->dev.parent = &interface->dev;
+ port->dev.driver = NULL;
+ port->dev.bus = &usb_serial_bus_type;
+ port->dev.release = &port_release;
+ device_initialize(&port->dev);
}
/* set up the endpoint information */
@@ -1077,15 +1077,10 @@ int usb_serial_probe(struct usb_interface *interface,
/* register all of the individual ports with the driver core */
for (i = 0; i < num_ports; ++i) {
port = serial->port[i];
- port->dev.parent = &interface->dev;
- port->dev.driver = NULL;
- port->dev.bus = &usb_serial_bus_type;
- port->dev.release = &port_release;
-
dev_set_name(&port->dev, "ttyUSB%d", port->number);
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
port->dev_state = PORT_REGISTERING;
- retval = device_register(&port->dev);
+ retval = device_add(&port->dev);
if (retval) {
dev_err(&port->dev, "Error registering port device, "
"continuing\n");
@@ -1103,39 +1098,7 @@ exit:
return 0;
probe_error:
- for (i = 0; i < num_bulk_in; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->read_urb);
- kfree(port->bulk_in_buffer);
- }
- for (i = 0; i < num_bulk_out; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->write_urb);
- kfree(port->bulk_out_buffer);
- }
- for (i = 0; i < num_interrupt_in; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->interrupt_in_urb);
- kfree(port->interrupt_in_buffer);
- }
- for (i = 0; i < num_interrupt_out; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- usb_free_urb(port->interrupt_out_urb);
- kfree(port->interrupt_out_buffer);
- }
-
- /* free up any memory that we allocated */
- for (i = 0; i < serial->num_port_pointers; ++i)
- kfree(serial->port[i]);
- kfree(serial);
+ usb_serial_put(serial);
return -EIO;
}
EXPORT_SYMBOL_GPL(usb_serial_probe);
@@ -1161,10 +1124,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (port) {
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) {
- /* The hangup will occur asynchronously but
- the object refcounts will sort out all the
- cleanup */
- tty_hangup(tty);
+ tty_vhangup(tty);
tty_kref_put(tty);
}
kill_traffic(port);
@@ -1189,8 +1149,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
}
serial->type->disconnect(serial);
- /* let the last holder of this object
- * cause it to be cleaned up */
+ /* let the last holder of this object cause it to be cleaned up */
usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
@@ -1246,6 +1205,8 @@ static const struct tty_operations serial_ops = {
.chars_in_buffer = serial_chars_in_buffer,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
+ .shutdown = serial_release,
+ .install = serial_install,
.proc_fops = &serial_proc_fops,
};
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 6148009..7b5bfc4 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -43,11 +43,10 @@ static struct usb_driver debug_driver = {
.no_dynamic_id = 1,
};
-static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port)
{
port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE;
- return usb_serial_generic_open(tty, port, filp);
+ return usb_serial_generic_open(tty, port);
}
/* This HW really does not support a serial break, so one will be
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index f5d0f64..1aa5d20 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -36,8 +36,7 @@
#define DRIVER_DESC "USB HandSpring Visor / Palm OS driver"
/* function prototypes for a handspring visor */
-static int visor_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp);
+static int visor_open(struct tty_struct *tty, struct usb_serial_port *port);
static void visor_close(struct usb_serial_port *port);
static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -273,8 +272,7 @@ static int stats;
/******************************************************************************
* Handspring Visor specific driver functions
******************************************************************************/
-static int visor_open(struct tty_struct *tty, struct usb_serial_port *port,
- struct file *filp)
+static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct visor_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 8d126dd..62424ee 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -146,7 +146,7 @@ static int whiteheat_firmware_attach(struct usb_serial *serial);
static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_release(struct usb_serial *serial);
static int whiteheat_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp);
+ struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
static int whiteheat_write(struct tty_struct *tty,
struct usb_serial_port *port,
@@ -259,7 +259,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,
__u8 *data, __u8 datasize);
static int firm_open(struct usb_serial_port *port);
static int firm_close(struct usb_serial_port *port);
-static int firm_setup_port(struct tty_struct *tty);
+static void firm_setup_port(struct tty_struct *tty);
static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
@@ -659,8 +659,7 @@ static void whiteheat_release(struct usb_serial *serial)
return;
}
-static int whiteheat_open(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
+static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int retval = 0;
@@ -1211,7 +1210,7 @@ static int firm_close(struct usb_serial_port *port)
}
-static int firm_setup_port(struct tty_struct *tty)
+static void firm_setup_port(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_port_settings port_settings;
@@ -1286,7 +1285,7 @@ static int firm_setup_port(struct tty_struct *tty)
port_settings.lloop = 0;
/* now send the message to the device */
- return firm_send_command(port, WHITEHEAT_SETUP_PORT,
+ firm_send_command(port, WHITEHEAT_SETUP_PORT,
(__u8 *)&port_settings, sizeof(port_settings));
}
OpenPOWER on IntegriCloud