aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/processor_idle.c4
-rw-r--r--drivers/ata/ahci.c255
-rw-r--r--drivers/ata/libata-core.c79
-rw-r--r--drivers/ata/libata-eh.c204
-rw-r--r--drivers/ata/libata-scsi.c63
-rw-r--r--drivers/ata/libata-sff.c4
-rw-r--r--drivers/ata/libata.h3
-rw-r--r--drivers/ata/pata_cs5520.c2
-rw-r--r--drivers/ata/pata_platform.c5
-rw-r--r--drivers/ata/pata_scc.c29
-rw-r--r--drivers/ata/sata_inic162x.c16
-rw-r--r--drivers/ata/sata_mv.c203
-rw-r--r--drivers/ata/sata_nv.c38
-rw-r--r--drivers/ata/sata_promise.c25
-rw-r--r--drivers/ata/sata_qstor.c18
-rw-r--r--drivers/ata/sata_sil.c25
-rw-r--r--drivers/ata/sata_sil24.c139
-rw-r--r--drivers/ata/sata_sis.c22
-rw-r--r--drivers/ata/sata_svw.c13
-rw-r--r--drivers/ata/sata_uli.c16
-rw-r--r--drivers/ata/sata_via.c27
-rw-r--r--drivers/ata/sata_vsc.c13
-rw-r--r--drivers/block/sunvdc.c26
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/hpet.c70
-rw-r--r--drivers/char/rtc.c30
-rw-r--r--drivers/char/serial167.c6
-rw-r--r--drivers/char/tpm/tpm_bios.c22
-rw-r--r--drivers/char/vme_scc.c8
-rw-r--r--drivers/char/watchdog/Kconfig2
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/input/input.c29
-rw-r--r--drivers/input/joystick/Kconfig7
-rw-r--r--drivers/input/joystick/xpad.c190
-rw-r--r--drivers/input/mouse/appletouch.c111
-rw-r--r--drivers/input/mouse/lifebook.c2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h36
-rw-r--r--drivers/input/touchscreen/Kconfig13
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ads7846.c80
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c189
-rw-r--r--drivers/kvm/kvm.h10
-rw-r--r--drivers/kvm/kvm_main.c76
-rw-r--r--drivers/kvm/mmu.c140
-rw-r--r--drivers/kvm/paging_tmpl.h2
-rw-r--r--drivers/kvm/x86_emulate.c26
-rw-r--r--drivers/lguest/interrupts_and_traps.c10
-rw-r--r--drivers/lguest/io.c2
-rw-r--r--drivers/lguest/lguest.c9
-rw-r--r--drivers/lguest/lguest_asm.S4
-rw-r--r--drivers/md/raid5.c4
-rw-r--r--drivers/media/common/ir-functions.c4
-rw-r--r--drivers/media/dvb/ttpci/av7110.c2
-rw-r--r--drivers/media/radio/radio-aimslab.c2
-rw-r--r--drivers/media/radio/radio-cadet.c4
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c3
-rw-r--r--drivers/media/video/bt866.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c2
-rw-r--r--drivers/media/video/bt8xx/bttvp.h4
-rw-r--r--drivers/media/video/c-qcam.c4
-rw-r--r--drivers/media/video/cx88/cx88-video.c8
-rw-r--r--drivers/media/video/cx88/cx88.h2
-rw-r--r--drivers/media/video/ivtv/Kconfig5
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c43
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c25
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c20
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c33
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c12
-rw-r--r--drivers/media/video/saa5249.c8
-rw-r--r--drivers/media/video/saa7110.c4
-rw-r--r--drivers/media/video/saa7134/saa7134.h2
-rw-r--r--drivers/media/video/tvaudio.c4
-rw-r--r--drivers/media/video/v4l2-common.c19
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/wm8739.c2
-rw-r--r--drivers/media/video/wm8775.c2
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/sky2.c7
-rw-r--r--drivers/net/sunvnet.c139
-rw-r--r--drivers/net/sunvnet.h11
-rw-r--r--drivers/of/Kconfig3
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/base.c275
-rw-r--r--drivers/of/device.c131
-rw-r--r--drivers/of/platform.c96
-rw-r--r--drivers/oprofile/buffer_sync.c3
-rw-r--r--drivers/oprofile/event_buffer.h20
-rw-r--r--drivers/oprofile/oprof.c28
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/sbus/sbus.c5
-rw-r--r--drivers/scsi/Kconfig2
-rw-r--r--drivers/scsi/NCR53C9x.c7
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/serial/suncore.c123
-rw-r--r--drivers/serial/suncore.h2
-rw-r--r--drivers/serial/sunhv.c13
-rw-r--r--drivers/serial/sunsab.c22
-rw-r--r--drivers/serial/sunsu.c23
-rw-r--r--drivers/serial/sunzilog.c24
-rw-r--r--drivers/usb/atm/cxacru.c3
-rw-r--r--drivers/usb/atm/speedtch.c7
-rw-r--r--drivers/usb/atm/ueagle-atm.c6
-rw-r--r--drivers/usb/atm/usbatm.c11
-rw-r--r--drivers/usb/class/cdc-acm.c18
-rw-r--r--drivers/usb/class/usblp.c27
-rw-r--r--drivers/usb/core/hcd.c131
-rw-r--r--drivers/usb/core/hub.c10
-rw-r--r--drivers/usb/core/message.c34
-rw-r--r--drivers/usb/core/sysfs.c53
-rw-r--r--drivers/usb/core/urb.c88
-rw-r--r--drivers/usb/gadget/Kconfig57
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c3454
-rw-r--r--drivers/usb/gadget/amd5536udc.h626
-rw-r--r--drivers/usb/gadget/ether.c4
-rw-r--r--drivers/usb/gadget/gadget_chips.h10
-rw-r--r--drivers/usb/gadget/m66592-udc.c255
-rw-r--r--drivers/usb/gadget/m66592-udc.h610
-rw-r--r--drivers/usb/gadget/serial.c25
-rw-r--r--drivers/usb/host/isp116x-hcd.c187
-rw-r--r--drivers/usb/host/r8a66597-hcd.c110
-rw-r--r--drivers/usb/host/r8a66597.h87
-rw-r--r--drivers/usb/host/u132-hcd.c17
-rw-r--r--drivers/usb/host/uhci-q.c59
-rw-r--r--drivers/usb/image/mdc800.c45
-rw-r--r--drivers/usb/image/microtek.c19
-rw-r--r--drivers/usb/misc/adutux.c59
-rw-r--r--drivers/usb/misc/appledisplay.c9
-rw-r--r--drivers/usb/misc/auerswald.c25
-rw-r--r--drivers/usb/misc/ftdi-elan.c21
-rw-r--r--drivers/usb/misc/iowarrior.c21
-rw-r--r--drivers/usb/misc/ldusb.c20
-rw-r--r--drivers/usb/misc/legousbtower.c28
-rw-r--r--drivers/usb/misc/phidgetkit.c13
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c13
-rw-r--r--drivers/usb/misc/usblcd.c11
-rw-r--r--drivers/usb/misc/usbtest.c4
-rw-r--r--drivers/usb/misc/uss720.c5
-rw-r--r--drivers/usb/serial/io_ti.c10
-rw-r--r--drivers/usb/serial/mos7720.c5
-rw-r--r--drivers/usb/serial/mos7840.c19
-rw-r--r--drivers/usb/serial/sierra.c119
-rw-r--r--drivers/usb/storage/dpcm.c56
-rw-r--r--drivers/usb/storage/onetouch.c13
-rw-r--r--drivers/usb/storage/unusual_devs.h18
-rw-r--r--drivers/video/aty/atyfb_base.c4
-rw-r--r--drivers/video/backlight/cr_bllcd.c2
-rw-r--r--drivers/video/igafb.c4
156 files changed, 7804 insertions, 2133 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 707650ab77a..3e1c442deff 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -8,6 +8,8 @@ source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
+source "drivers/of/Kconfig"
+
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 0ea8e3237c0..a9e4c5f922a 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -86,3 +86,4 @@ obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
+obj-$(CONFIG_OF) += of/
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc782991..bb5d23be426 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -475,7 +475,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C2, so notify users */
mark_tsc_unstable("possible TSC halt in C2");
#endif
@@ -517,7 +517,7 @@ static void acpi_processor_idle(void)
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C3, so notify users */
mark_tsc_unstable("TSC halts in C3");
#endif
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9f304..06f212ff2b4 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -99,6 +99,7 @@ enum {
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -113,11 +114,11 @@ enum {
PORT_TFDATA = 0x20, /* taskfile data */
PORT_SIG = 0x24, /* device TF signature */
PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR = 0x28, /* SATA phy register block */
PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@@ -216,8 +217,8 @@ struct ahci_port_priv {
unsigned int ncq_saw_sdb:1;
};
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static void ahci_irq_clear(struct ata_port *ap);
@@ -417,7 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
- { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
+ { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
+ { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
+ { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -545,13 +549,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
- /* some chips lie about 64bit support */
+ /* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
+ if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do NCQ, turning off CAP_NCQ\n");
+ cap &= ~HOST_CAP_NCQ;
+ }
+
/* fixup zero port_map */
if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -625,38 +635,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return 0xffffffffU;
- }
+ static const int offset[] = {
+ [SCR_STATUS] = PORT_SCR_STAT,
+ [SCR_CONTROL] = PORT_SCR_CTL,
+ [SCR_ERROR] = PORT_SCR_ERR,
+ [SCR_ACTIVE] = PORT_SCR_ACT,
+ [SCR_NOTIFICATION] = PORT_SCR_NTF,
+ };
+ struct ahci_host_priv *hpriv = ap->host->private_data;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (sc_reg < ARRAY_SIZE(offset) &&
+ (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+ return offset[sc_reg];
+ return 0;
}
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ *val = readl(port_mmio + offset);
+ return 0;
}
+ return -EINVAL;
+}
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ writel(val, port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
}
static void ahci_start_engine(struct ata_port *ap)
@@ -948,37 +965,87 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
+ int busy, rc;
+
+ /* do we need to kick the port? */
+ busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !force_restart)
+ return 0;
+
+ /* stop engine */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ goto out_restart;
- if (!(hpriv->cap & HOST_CAP_CLO))
- return -EOPNOTSUPP;
+ /* need to do CLO? */
+ if (!busy) {
+ rc = 0;
+ goto out_restart;
+ }
+ if (!(hpriv->cap & HOST_CAP_CLO)) {
+ rc = -EOPNOTSUPP;
+ goto out_restart;
+ }
+
+ /* perform CLO */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD);
+ rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO)
- return -EIO;
+ rc = -EIO;
- return 0;
+ /* restart engine */
+ out_restart:
+ ahci_start_engine(ap);
+ return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+ struct ata_taskfile *tf, int is_cmd, u16 flags,
+ unsigned long timeout_msec)
{
+ const u32 cmd_fis_len = 5; /* five dwords */
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
- const u32 cmd_fis_len = 5; /* five dwords */
+ u8 *fis = pp->cmd_tbl;
+ u32 tmp;
+
+ /* prep the command */
+ ata_tf_to_fis(tf, pmp, is_cmd, fis);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+ /* issue & wait */
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (timeout_msec) {
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+ 1, timeout_msec);
+ if (tmp & 0x1) {
+ ahci_kick_engine(ap, 1);
+ return -EBUSY;
+ }
+ } else
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
const char *reason = NULL;
+ unsigned long now, msecs;
struct ata_taskfile tf;
- u32 tmp;
- u8 *fis;
int rc;
DPRINTK("ENTER\n");
@@ -990,43 +1057,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
- if (rc) {
- reason = "failed to stop engine";
- goto fail_restart;
- }
-
- /* check BUSY/DRQ, perform Command List Override if necessary */
- if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
- rc = ahci_clo(ap);
-
- if (rc == -EOPNOTSUPP) {
- reason = "port busy but CLO unavailable";
- goto fail_restart;
- } else if (rc) {
- reason = "port busy but CLO failed";
- goto fail_restart;
- }
- }
-
- /* restart engine */
- ahci_start_engine(ap);
+ rc = ahci_kick_engine(ap, 1);
+ if (rc)
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to reset engine (errno=%d)", rc);
ata_tf_init(ap->device, &tf);
- fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0,
- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+ msecs = 0;
+ now = jiffies;
+ if (time_after(now, deadline))
+ msecs = jiffies_to_msecs(deadline - now);
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
- if (tmp & 0x1) {
+ if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+ AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
@@ -1036,14 +1082,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+ ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -1066,13 +1106,17 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return 0;
- fail_restart:
- ahci_start_engine(ap);
fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(ap, class, 0, deadline);
+}
+
static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
@@ -1088,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
tf.command = 0x80;
- ata_tf_to_fis(&tf, d2h_fis, 0);
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_std_hardreset(ap, class, deadline);
@@ -1106,6 +1150,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
+ u32 serror;
int rc;
DPRINTK("ENTER\n");
@@ -1116,7 +1161,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
deadline);
/* vt8251 needs SError cleared for the port to operate */
- ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+ ahci_scr_read(ap, SCR_ERROR, &serror);
+ ahci_scr_write(ap, SCR_ERROR, serror);
ahci_start_engine(ap);
@@ -1205,7 +1251,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1238,7 +1284,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_ehi_clear_desc(ehi);
/* AHCI needs SError cleared; otherwise, it might lock up */
- serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_read(ap, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror);
/* analyze @irq_stat */
@@ -1262,12 +1308,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
if (irq_stat & PORT_IRQ_IF_ERR) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", interface fatal error");
+ ata_ehi_push_desc(ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
@@ -1276,7 +1322,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
err_mask |= AC_ERR_HSM;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+ ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
unk[0], unk[1], unk[2], unk[3]);
}
@@ -1512,11 +1558,17 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED) {
- /* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+ ahci_power_up(ap);
+ ahci_start_port(ap);
+
+ return 0;
}
#ifdef CONFIG_PM
@@ -1536,14 +1588,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
return rc;
}
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- return 0;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1734,12 +1778,13 @@ static void ahci_print_info(struct ata_host *host)
dev_printk(KERN_INFO, &pdev->dev,
"flags: "
- "%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
,
cap & (1 << 31) ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 29) ? "sntf " : "",
cap & (1 << 28) ? "ilck " : "",
cap & (1 << 27) ? "stag " : "",
cap & (1 << 26) ? "pm " : "",
@@ -1794,7 +1839,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_save_initial_config(pdev, &pi, hpriv);
/* prepare host */
- if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+ if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
@@ -1808,10 +1853,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *port_mmio = ahci_port_base(ap);
/* standard SATA port setup */
- if (hpriv->port_map & (1 << i)) {
+ if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
- ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
- }
/* disabled/not-implemented port */
else
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 88e2dd0983b..6001aae0b88 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
- * @fis: Buffer into which data will output
* @pmp: Port multiplier port
+ * @is_cmd: This FIS is for command
+ * @fis: Buffer into which data will output
*
* Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device).
@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* Inherited from caller.
*/
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = pmp & 0xf; /* Port multiplier number*/
+ if (is_cmd)
+ fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
+
fis[2] = tf->command;
fis[3] = tf->feature;
@@ -2387,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
u32 sstatus, spd, mask;
int rc, highbit;
+ if (!sata_scr_valid(ap))
+ return -EOPNOTSUPP;
+
+ /* If SCR can be read, use it to determine the current SPD.
+ * If not, use cached value in ap->sata_spd.
+ */
rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
- if (rc)
- return rc;
+ if (rc == 0)
+ spd = (sstatus >> 4) & 0xf;
+ else
+ spd = ap->sata_spd;
mask = ap->sata_spd_limit;
if (mask <= 1)
return -EINVAL;
+
+ /* unconditionally mask off the highest bit */
highbit = fls(mask) - 1;
mask &= ~(1 << highbit);
- spd = (sstatus >> 4) & 0xf;
- if (spd <= 1)
- return -EINVAL;
- spd--;
- mask &= (1 << spd) - 1;
+ /* Mask off all speeds higher than or equal to the current
+ * one. Force 1.5Gbps if current SPD is not available.
+ */
+ if (spd > 1)
+ mask &= (1 << (spd - 1)) - 1;
+ else
+ mask &= 1;
+
+ /* were we already at the bottom? */
if (!mask)
return -EINVAL;
@@ -3251,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
last = cur;
last_jiffies = jiffies;
- /* check deadline */
+ /* Check deadline. If debouncing failed, return
+ * -EPIPE to tell upper layer to lower link speed.
+ */
if (time_after(jiffies, deadline))
- return -EBUSY;
+ return -EPIPE;
}
}
@@ -3769,6 +3787,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
/* Devices with NCQ limits */
@@ -5729,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap)
*/
int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
{
- if (sata_scr_valid(ap)) {
- *val = ap->ops->scr_read(ap, reg);
- return 0;
- }
+ if (sata_scr_valid(ap))
+ return ap->ops->scr_read(ap, reg, val);
return -EOPNOTSUPP;
}
@@ -5754,10 +5771,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
*/
int sata_scr_write(struct ata_port *ap, int reg, u32 val)
{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- return 0;
- }
+ if (sata_scr_valid(ap))
+ return ap->ops->scr_write(ap, reg, val);
return -EOPNOTSUPP;
}
@@ -5778,10 +5793,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
*/
int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
{
+ int rc;
+
if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- ap->ops->scr_read(ap, reg);
- return 0;
+ rc = ap->ops->scr_write(ap, reg, val);
+ if (rc == 0)
+ rc = ap->ops->scr_read(ap, reg, &val);
+ return rc;
}
return -EOPNOTSUPP;
}
@@ -5993,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev)
/* SATA spd limit is bound to the first device */
ap->sata_spd_limit = ap->hw_sata_spd_limit;
+ ap->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
@@ -6058,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
+ init_timer_deferrable(&ap->fastdrain_timer);
+ ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+ ap->fastdrain_timer.data = (unsigned long)ap;
ap->cbl = ATA_CBL_NONE;
@@ -6434,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_scsi_scan_host(ap);
+ ata_scsi_scan_host(ap, 1);
}
return 0;
@@ -6942,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9aa62a0754f..ac6ceed4bb6 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -56,6 +56,7 @@ enum {
*/
enum {
ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
+ ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
};
/* The following table determines how we sequence resets. Each entry
@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
{ }
#endif /* CONFIG_PM */
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+ va_list args)
+{
+ ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+ ATA_EH_DESC_LEN - ehi->desc_len,
+ fmt, args);
+}
+
+/**
+ * __ata_ehi_push_desc - push error description without adding separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_push_desc - push error description with separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ * If @ehi->desc is not empty, ", " is added in-between.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ if (ehi->desc_len)
+ __ata_ehi_push_desc(ehi, ", ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_clear_desc - clean error description
+ * @ehi: target EHI
+ *
+ * Clear @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+ ehi->desc[0] = '\0';
+ ehi->desc_len = 0;
+}
+
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
{
@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ /* kill fast drain timer */
+ del_timer_sync(&ap->fastdrain_timer);
+
/* process port resume request */
ata_eh_handle_port_resume(ap);
@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
DPRINTK("EXIT\n");
}
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+ unsigned int tag;
+ int nr = 0;
+
+ /* count only non-internal commands */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+ if (ata_qc_from_tag(ap, tag))
+ nr++;
+
+ return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+ struct ata_port *ap = (void *)arg;
+ unsigned long flags;
+ int cnt;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ cnt = ata_eh_nr_in_flight(ap);
+
+ /* are we done? */
+ if (!cnt)
+ goto out_unlock;
+
+ if (cnt == ap->fastdrain_cnt) {
+ unsigned int tag;
+
+ /* No progress during the last interval, tag all
+ * in-flight qcs as timed out and freeze the port.
+ */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ }
+
+ ata_port_freeze(ap);
+ } else {
+ /* some qcs have finished, give it another chance */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires =
+ jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+ }
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ * @ap: target ATA port
+ * @fastdrain: activate fast drain
+ *
+ * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ * is non-zero and EH wasn't pending before. Fast drain ensures
+ * that EH kicks in in timely manner.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+ int cnt;
+
+ /* already scheduled? */
+ if (ap->pflags & ATA_PFLAG_EH_PENDING)
+ return;
+
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+ if (!fastdrain)
+ return;
+
+ /* do we have in-flight qcs? */
+ cnt = ata_eh_nr_in_flight(ap);
+ if (!cnt)
+ return;
+
+ /* activate fast drain */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+}
+
/**
* ata_qc_schedule_eh - schedule qc for error handling
* @qc: command to schedule error handling for
@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_INITIALIZING)
return;
- ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
scsi_schedule_eh(ap->scsi_host);
DPRINTK("port EH scheduled\n");
@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
WARN_ON(!ap->ops->error_handler);
+ /* we're gonna abort all commands, no need for fast drain */
+ ata_eh_set_pending(ap, 0);
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf));
- qc->err_mask |= AC_ERR_DEV;
+ qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
if (rc == 0) {
ehc->i.serror |= serror;
ata_eh_analyze_serror(ap);
- } else if (rc != -EOPNOTSUPP)
+ } else if (rc != -EOPNOTSUPP) {
+ /* SError read failed, force hardreset and probing */
+ ata_ehi_schedule_probe(&ehc->i);
ehc->i.action |= ATA_EH_HARDRESET;
+ ehc->i.err_mask |= AC_ERR_OTHER;
+ }
/* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap);
@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap)
ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen);
if (desc)
- ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else {
ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
"SAct 0x%x SErr 0x%x action 0x%x%s\n",
ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen);
if (desc)
- ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+ ata_port_printk(ap, KERN_ERR, "%s\n", desc);
}
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap)
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n "
"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
- "Emask 0x%x (%s)\n",
+ "Emask 0x%x (%s)%s\n",
cmd->command, cmd->feature, cmd->nsect,
cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect,
@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap)
res->lbal, res->lbam, res->lbah,
res->hob_feature, res->hob_nsect,
res->hob_lbal, res->hob_lbam, res->hob_lbah,
- res->device, qc->err_mask, ata_err_string(qc->err_mask));
+ res->device, qc->err_mask, ata_err_string(qc->err_mask),
+ qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
}
}
@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
} else
ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
- return rc;
+ goto out;
}
}
@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* prereset told us not to reset, bang classes and return */
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_NONE;
- return 0;
+ rc = 0;
+ goto out;
}
/* did prereset() screw up? if so, fix up to avoid oopsing */
@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
classes[0] == ATA_DEV_UNKNOWN) {
ata_port_printk(ap, KERN_ERR,
"classification failed\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
}
@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
schedule_timeout_uninterruptible(delta);
}
- if (reset == hardreset &&
+ if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
sata_down_spd_limit(ap);
if (hardreset)
@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
}
if (rc == 0) {
+ u32 sstatus;
+
/* After the reset, the device state is PIO 0 and the
* controller state is undefined. Record the mode.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].pio_mode = XFER_PIO_0;
+ /* record current link speed */
+ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
+ ap->sata_spd = (sstatus >> 4) & 0xf;
+
if (postreset)
postreset(ap, classes);
@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
-
+ out:
+ /* clear hotplug flag */
+ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
return rc;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22da07a..12ac0b511f7 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
return rc;
}
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
+ int tries = 5;
+ struct ata_device *last_failed_dev = NULL;
+ struct ata_device *dev;
unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED)
return;
+ repeat:
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
struct scsi_device *sdev;
+ dev = &ap->device[i];
+
if (!ata_dev_enabled(dev) || dev->sdev)
continue;
@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
scsi_device_put(sdev);
}
}
+
+ /* If we scanned while EH was in progress or allocation
+ * failure occurred, scan would have failed silently. Check
+ * whether all devices are attached.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ break;
+ }
+ if (i == ATA_MAX_DEVICES)
+ return;
+
+ /* we're missing some SCSI devices */
+ if (sync) {
+ /* If caller requested synchrnous scan && we've made
+ * any progress, sleep briefly and repeat.
+ */
+ if (dev != last_failed_dev) {
+ msleep(100);
+ last_failed_dev = dev;
+ goto repeat;
+ }
+
+ /* We might be failing to detect boot device, give it
+ * a few more chances.
+ */
+ if (--tries) {
+ msleep(100);
+ goto repeat;
+ }
+
+ ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+ "failed without making any progress,\n"
+ " switching to async\n");
+ }
+
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
}
/**
@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
}
/* scan for new ones */
- ata_scsi_scan_host(ap);
-
- /* If we scanned while EH was in progress, scan would have
- * failed silently. Requeue if there are enabled but
- * unattached devices.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
- round_jiffies_relative(HZ));
- break;
- }
- }
+ ata_scsi_scan_host(ap, 0);
DPRINTK("EXIT\n");
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index ca7d2245d68..6c289c7b132 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,5 +1,5 @@
/*
- * libata-bmdma.c - helper library for PCI IDE BMDMA
+ * libata-sff.c - helper library for PCI IDE BMDMA
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org
@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = ioread8(ioaddr->lbal_addr);
tf->hob_lbam = ioread8(ioaddr->lbam_addr);
tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
}
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5f2e9..564cd234c80 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
/* libata-scsi.c */
extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap);
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 6bf037d82b5..7dc76e71bd5 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -275,7 +275,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
for (i = 0; i < 2; i++) {
static const int irq[] = { 14, 15 };
- struct ata_port *ap = host->ports[0];
+ struct ata_port *ap = host->ports[i];
if (ata_port_is_dummy(ap))
continue;
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 79f841bca59..a909f793ffc 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
pata_platform_setup_port(&ap->ioaddr, pp_info);
/* activate */
- return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
- pp_info->irq_flags, &pata_platform_sht);
+ return ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_interrupt, pp_info ? pp_info->irq_flags
+ : 0, &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index c55667e0eb6..36cdbd2b0bd 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
else
offset = 0; /* 100MHz */
- /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
- if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
- printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
- speed = XFER_UDMA_4;
- }
-
if (speed >= XFER_UDMA_0)
idx = speed - XFER_UDMA_0;
else
@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
}
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+ if (adev->class == ATA_DEV_ATAPI &&
+ (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+ printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+ mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(adev, mask);
+}
+
/**
* scc_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = in_be32(ioaddr->lbal_addr);
tf->hob_lbam = in_be32(ioaddr->lbam_addr);
tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+ out_be32(ioaddr->ctl_addr, tf->ctl);
+ ap->last_ctl = tf->ctl;
}
}
@@ -741,7 +748,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
return host_stat;
/* errata A252,A308 workaround: Step4 */
- if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+ if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
@@ -752,11 +759,11 @@ static u8 scc_bmdma_status (struct ata_port *ap)
if ((qc->tf.protocol == ATA_PROT_DMA &&
qc->dev->xfer_mode > XFER_UDMA_4)) {
if (!(int_status & INTSTS_ACTEINT)) {
- printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
- ap->print_id, retry);
+ printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+ ap->print_id);
host_stat |= ATA_DMA_ERR;
if (retry++)
- ap->udma_mask >>= 1;
+ ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
} else
retry = 0;
}
@@ -1016,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = {
.port_disable = ata_port_disable,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
- .mode_filter = ata_pci_default_filter,
+ .mode_filter = scc_mode_filter,
.tf_load = scc_tf_load,
.tf_read = scc_tf_read,
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3de183461c3..a9c948d7604 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
writew(ctl, idma_ctl);
}
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr;
- u32 val;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return 0xffffffffU;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
- val = readl(scr_addr + scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + scr_map[sc_reg] * 4);
/* this controller has stuck DIAG.N, ignore it */
if (sc_reg == SCR_ERROR)
- val &= ~SERR_PHYRDY_CHG;
- return val;
+ *val &= ~SERR_PHYRDY_CHG;
+ return 0;
}
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
+ return 0;
}
/*
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index fb8a749423c..8ec520885b9 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -35,8 +35,6 @@
6) Add port multiplier support (intermediate)
- 7) Test and verify 3.0 Gbps support
-
8) Develop a low-power-consumption strategy, and implement it.
9) [Experiment, low priority] See if ATAPI can be supported using
@@ -227,26 +225,26 @@ enum {
EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
EDMA_ERR_IRQ_MASK_OFS = 0xc,
- EDMA_ERR_D_PAR = (1 << 0),
- EDMA_ERR_PRD_PAR = (1 << 1),
- EDMA_ERR_DEV = (1 << 2),
- EDMA_ERR_DEV_DCON = (1 << 3),
- EDMA_ERR_DEV_CON = (1 << 4),
- EDMA_ERR_SERR = (1 << 5),
+ EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */
+ EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */
+ EDMA_ERR_DEV = (1 << 2), /* device error */
+ EDMA_ERR_DEV_DCON = (1 << 3), /* device disconnect */
+ EDMA_ERR_DEV_CON = (1 << 4), /* device connected */
+ EDMA_ERR_SERR = (1 << 5), /* SError bits [WBDST] raised */
EDMA_ERR_SELF_DIS = (1 << 7), /* Gen II/IIE self-disable */
EDMA_ERR_SELF_DIS_5 = (1 << 8), /* Gen I self-disable */
- EDMA_ERR_BIST_ASYNC = (1 << 8),
+ EDMA_ERR_BIST_ASYNC = (1 << 8), /* BIST FIS or Async Notify */
EDMA_ERR_TRANS_IRQ_7 = (1 << 8), /* Gen IIE transprt layer irq */
- EDMA_ERR_CRBQ_PAR = (1 << 9),
- EDMA_ERR_CRPB_PAR = (1 << 10),
- EDMA_ERR_INTRL_PAR = (1 << 11),
- EDMA_ERR_IORDY = (1 << 12),
- EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+ EDMA_ERR_CRQB_PAR = (1 << 9), /* CRQB parity error */
+ EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */
+ EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */
+ EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */
+ EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */
EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
- EDMA_ERR_LNK_DATA_RX = (0xf << 17),
- EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
- EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
- EDMA_ERR_TRANS_PROTO = (1 << 31),
+ EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */
+ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */
+ EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */
+ EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */
EDMA_ERR_OVERRUN_5 = (1 << 5),
EDMA_ERR_UNDERRUN_5 = (1 << 6),
EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
@@ -255,7 +253,7 @@ enum {
EDMA_ERR_DEV_CON |
EDMA_ERR_SERR |
EDMA_ERR_SELF_DIS |
- EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRQB_PAR |
EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR |
EDMA_ERR_IORDY |
@@ -270,7 +268,7 @@ enum {
EDMA_ERR_OVERRUN_5 |
EDMA_ERR_UNDERRUN_5 |
EDMA_ERR_SELF_DIS_5 |
- EDMA_ERR_CRBQ_PAR |
+ EDMA_ERR_CRQB_PAR |
EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR |
EDMA_ERR_IORDY,
@@ -286,10 +284,10 @@ enum {
EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
EDMA_RSP_Q_PTR_SHIFT = 3,
- EDMA_CMD_OFS = 0x28,
- EDMA_EN = (1 << 0),
- EDMA_DS = (1 << 1),
- ATA_RST = (1 << 2),
+ EDMA_CMD_OFS = 0x28, /* EDMA command register */
+ EDMA_EN = (1 << 0), /* enable EDMA */
+ EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
+ ATA_RST = (1 << 2), /* reset trans/link/phy */
EDMA_IORDY_TMOUT = 0x34,
EDMA_ARB_CFG = 0x38,
@@ -301,14 +299,13 @@ enum {
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
MV_HP_ERRATA_XX42A0 = (1 << 5),
- MV_HP_GEN_I = (1 << 6),
- MV_HP_GEN_II = (1 << 7),
- MV_HP_GEN_IIE = (1 << 8),
+ MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
+ MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
+ MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
/* Port private flags (pp_flags) */
- MV_PP_FLAG_EDMA_EN = (1 << 0),
- MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
- MV_PP_FLAG_HAD_A_RESET = (1 << 2),
+ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
+ MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -318,8 +315,12 @@ enum {
enum {
MV_DMA_BOUNDARY = 0xffffffffU,
+ /* mask of register bits containing lower 32 bits
+ * of EDMA request queue DMA address
+ */
EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
+ /* ditto, for response queue */
EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
};
@@ -403,10 +404,10 @@ struct mv_host_priv {
};
static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -823,7 +824,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
}
/**
- * mv_stop_dma - Disable eDMA engine
+ * __mv_stop_dma - Disable eDMA engine
* @ap: ATA channel to manipulate
*
* Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +833,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
* LOCKING:
* Inherited from caller.
*/
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
@@ -865,6 +866,18 @@ static int mv_stop_dma(struct ata_port *ap)
return err;
}
+static int mv_stop_dma(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ rc = __mv_stop_dma(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ return rc;
+}
+
#ifdef ATA_DEBUG
static void mv_dump_mem(void __iomem *start, unsigned bytes)
{
@@ -961,22 +974,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
- return readl(mv_ap_base(ap) + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
+ if (ofs != 0xffffffffU) {
writelfl(val, mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1046,7 @@ static int mv_port_start(struct ata_port *ap)
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
dma_addr_t mem_dma;
+ unsigned long flags;
int rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1085,14 @@ static int mv_port_start(struct ata_port *ap)
pp->sg_tbl = mem;
pp->sg_tbl_dma = mem_dma;
+ spin_lock_irqsave(&ap->host->lock, flags);
+
mv_edma_cfg(ap, hpriv, port_mmio);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
/* Don't turn on EDMA here...do it before DMA commands only. Else
* we'll be unable to send non-data, PIO, etc due to restricted access
* to shadow regs.
@@ -1090,11 +1112,7 @@ static int mv_port_start(struct ata_port *ap)
*/
static void mv_port_stop(struct ata_port *ap)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
- spin_unlock_irqrestore(&ap->host->lock, flags);
}
/**
@@ -1325,7 +1343,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
*/
- mv_stop_dma(ap);
+ __mv_stop_dma(ap);
return ata_qc_issue_prot(qc);
}
@@ -1393,16 +1411,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_DEV)
err_mask |= AC_ERR_DEV;
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
- EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+ EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
- ata_ehi_push_desc(ehi, ", parity error");
+ ata_ehi_push_desc(ehi, "parity error");
}
if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
- ", dev disconnect" : ", dev connect");
+ "dev disconnect" : "dev connect");
}
if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1429,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
struct mv_port_priv *pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- ata_ehi_push_desc(ehi, ", EDMA self-disable");
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
}
} else {
eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,7 +1437,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
if (edma_err_cause & EDMA_ERR_SELF_DIS) {
struct mv_port_priv *pp = ap->private_data;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
- ata_ehi_push_desc(ehi, ", EDMA self-disable");
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
}
if (edma_err_cause & EDMA_ERR_SERR) {
@@ -1489,33 +1507,30 @@ static void mv_intr_edma(struct ata_port *ap)
while (1) {
u16 status;
+ unsigned int tag;
/* get s/w response queue last-read pointer, and compare */
out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
if (in_index == out_index)
break;
-
/* 50xx: get active ATA command */
- if (IS_GEN_I(hpriv))
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (IS_GEN_I(hpriv))
+ tag = ap->active_tag;
- /* 60xx: get active ATA command via tag, to enable support
- * for queueing. this works transparently for queued and
- * non-queued modes.
+ /* Gen II/IIE: get active ATA command via tag, to enable
+ * support for queueing. this works transparently for
+ * queued and non-queued modes.
*/
- else {
- unsigned int tag;
+ else if (IS_GEN_II(hpriv))
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_6) & 0x3f;
- if (IS_GEN_II(hpriv))
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_6) & 0x3f;
- else
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_7) & 0x3f;
+ else /* IS_GEN_IIE */
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_7) & 0x3f;
- qc = ata_qc_from_tag(ap, tag);
- }
+ qc = ata_qc_from_tag(ap, tag);
/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
* bits (WARNING: might not necessarily be associated
@@ -1535,7 +1550,7 @@ static void mv_intr_edma(struct ata_port *ap)
ata_qc_complete(qc);
}
- /* advance software response queue pointer, to
+ /* advance software response queue pointer, to
* indicate (after the loop completes) to hardware
* that we have consumed a response queue entry.
*/
@@ -1741,26 +1756,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
- return readl(addr + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
+ if (ofs != 0xffffffffU) {
writelfl(val, addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,9 +2157,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
- DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
+
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", status, serror, scontrol);
+ }
+#endif
/* Issue COMRESET via SControl */
comreset_retry:
@@ -2164,9 +2191,17 @@ comreset_retry:
(retry-- > 0))
goto comreset_retry;
- DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
+
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+ }
+#endif
if (ata_port_offline(ap)) {
*class = ATA_DEV_NONE;
@@ -2209,7 +2244,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
struct mv_port_priv *pp = ap->private_data;
struct ata_eh_context *ehc = &ap->eh_context;
int rc;
-
+
rc = mv_stop_dma(ap);
if (rc)
ehc->i.action |= ATA_EH_HARDRESET;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index db81e3efa5e..0b58c4df6fd 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
int freeze = 0;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+ __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
if (flags & NV_CPB_RESP_ATA_ERR) {
- ata_ehi_push_desc(ehi, ": ATA error");
+ ata_ehi_push_desc(ehi, "ATA error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CMD_ERR) {
- ata_ehi_push_desc(ehi, ": CMD error");
+ ata_ehi_push_desc(ehi, "CMD error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CPB_ERR) {
- ata_ehi_push_desc(ehi, ": CPB error");
+ ata_ehi_push_desc(ehi, "CPB error");
ehi->err_mask |= AC_ERR_SYSTEM;
freeze = 1;
} else {
/* notifier error, but no error in CPB flags? */
+ ata_ehi_push_desc(ehi, "unknown");
ehi->err_mask |= AC_ERR_OTHER;
freeze = 1;
}
@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
struct ata_eh_info *ehi = &ap->eh_info;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+ __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
if (status & NV_ADMA_STAT_TIMEOUT) {
ehi->err_mask |= AC_ERR_SYSTEM;
- ata_ehi_push_desc(ehi, ": timeout");
+ ata_ehi_push_desc(ehi, "timeout");
} else if (status & NV_ADMA_STAT_HOTPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hotplug");
+ ata_ehi_push_desc(ehi, "hotplug");
} else if (status & NV_ADMA_STAT_HOTUNPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hot unplug");
+ ata_ehi_push_desc(ehi, "hot unplug");
} else if (status & NV_ADMA_STAT_SERROR) {
/* let libata analyze SError and figure out the cause */
- ata_ehi_push_desc(ehi, ": SError");
- }
+ ata_ehi_push_desc(ehi, "SError");
+ } else
+ ata_ehi_push_desc(ehi, "unknown");
ata_port_freeze(ap);
continue;
}
@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret;
}
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void nv_nf2_freeze(struct ata_port *ap)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d2fcb9a6bec..d39ebc23c4a 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -128,8 +128,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA;
}
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS;
- if (sata_scr_valid(ap))
- ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+ if (sata_scr_valid(ap)) {
+ u32 serror;
+
+ pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+ ehi->serror |= serror;
+ }
qc->err_mask |= ac_err_mask;
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554da89b..c8f9242e7f4 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state;
};
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap)
ata_eng_timeout(ap);
}
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return ~0U;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
buf[28] = dflags;
/* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4598d..db676375895 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
return NULL;
}
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
- return readl(mmio);
- return 0xffffffffU;
+
+ if (mmio) {
+ *val = readl(mmio);
+ return 0;
+ }
+ return -EINVAL;
}
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
+
+ if (mmio) {
writel(val, mmio);
+ return 0;
+ }
+ return -EINVAL;
}
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- serror = sil_scr_read(ap, SCR_ERROR);
+ sil_scr_read(ap, SCR_ERROR, &serror);
sil_scr_write(ap, SCR_ERROR, serror);
/* Trigger hotplug and accumulate SError only if the
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30ebe2..46fbbe7f121 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -326,8 +326,8 @@ struct sil24_port_priv {
static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
}
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
{
- struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = ap->ioaddr.cmd_addr;
- struct sil24_prb __iomem *prb = port;
+ struct sil24_prb __iomem *prb;
u8 fis[6 * 4];
- memcpy_fromio(fis, prb->fis, 6 * 4);
- ata_tf_from_fis(fis, &pp->tf);
+ prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+ memcpy_fromio(fis, prb->fis, sizeof(fis));
+ ata_tf_from_fis(fis, tf);
}
static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +488,30 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3,
};
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
- return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
- return 0xffffffffU;
+ return -EINVAL;
}
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
+ return -EINVAL;
}
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap)
return 0;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+ const struct ata_taskfile *tf,
+ int is_cmd, u32 ctrl,
+ unsigned long timeout_msec)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
- u32 mask, irq_stat;
+ u32 irq_enabled, irq_mask, irq_stat;
+ int rc;
+
+ prb->ctrl = cpu_to_le16(ctrl);
+ ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+ /* temporarily plug completion and error interrupts */
+ irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+ writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+ irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+ 10, timeout_msec);
+
+ writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+ if (irq_stat & PORT_IRQ_COMPLETE)
+ rc = 0;
+ else {
+ /* force port into known state */
+ sil24_init_port(ap);
+
+ if (irq_stat & PORT_IRQ_ERROR)
+ rc = -EIO;
+ else
+ rc = -EBUSY;
+ }
+
+ /* restore IRQ enabled */
+ writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+ return rc;
+}
+
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
+ unsigned long timeout_msec = 0;
+ struct ata_taskfile tf;
const char *reason;
+ int rc;
DPRINTK("ENTER\n");
@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
}
/* do SRST */
- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
- prb->fis[1] = 0; /* no PMP yet */
-
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, jiffies_to_msecs(deadline - jiffies));
-
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- if (irq_stat & PORT_IRQ_ERROR)
- reason = "SRST command error";
- else
- reason = "timeout";
+ if (time_after(deadline, jiffies))
+ timeout_msec = jiffies_to_msecs(deadline - jiffies);
+
+ ata_tf_init(ap->device, &tf); /* doesn't really matter */
+ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+ timeout_msec);
+ if (rc == -EBUSY) {
+ reason = "timeout";
+ goto err;
+ } else if (rc) {
+ reason = "SRST command error";
goto err;
}
- sil24_update_tf(ap);
- *class = ata_dev_classify(&pp->tf);
+ sil24_read_tf(ap, 0, &tf);
+ *class = ata_dev_classify(&tf);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
return -EIO;
}
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(ap, class, 0, deadline);
+}
+
static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0;
u32 irq_stat;
@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s",
- irq_stat & PORT_IRQ_PHYRDY_CHG ?
- "PHY RDY changed" : "device exchanged");
+ ata_ehi_push_desc(ehi, "%s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
freeze = 1;
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi , ", unknown FIS");
+ ata_ehi_push_desc(ehi, "unknown FIS");
freeze = 1;
}
@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap)
if (ci && ci->desc) {
err_mask |= ci->err_mask;
action |= ci->action;
- ata_ehi_push_desc(ehi, ", %s", ci->desc);
+ ata_ehi_push_desc(ehi, "%s", ci->desc);
} else {
err_mask |= AC_ERR_OTHER;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown command error %d",
+ ata_ehi_push_desc(ehi, "unknown command error %d",
cerr);
}
/* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- sil24_update_tf(ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
} else
ehi->err_mask |= err_mask;
@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap)
static void sil24_finish_qc(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+
if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(qc->ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
}
static inline void sil24_host_intr(struct ata_port *ap)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 33716b00c6b..31a2f55aae6 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -64,8 +64,8 @@ enum {
};
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
pci_write_config_dword(pdev, cfg_addr+0x10, val);
}
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 val, val2 = 0;
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(ap, sc_reg);
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+ *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+ *val &= 0xfffffffb;
- return (val | val2) & 0xfffffffb;
+ return 0;
}
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
}
+ return 0;
}
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 63fe99afd59..92e87707503 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index b52f83ab056..78c28512f01 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -57,8 +57,8 @@ struct uli_priv {
};
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
pci_write_config_dword(pdev, cfg_addr, val);
}
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return uli_scr_cfg_read(ap, sc_reg);
+ *val = uli_scr_cfg_read(ap, sc_reg);
+ return 0;
}
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
- return;
+ return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val);
+ return 0;
}
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c4124475f75..86b7bfc1732 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -72,8 +72,8 @@ enum {
};
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return -EINVAL;
+ *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
static void svia_noop_freeze(struct ata_port *ap)
@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
/* Resume phy. This is the old SATA resume sequence */
svia_scr_write(ap, SCR_CONTROL, 0x300);
- svia_scr_read(ap, SCR_CONTROL); /* flush */
+ svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */
- sstatus = svia_scr_read(ap, SCR_STATUS);
- scontrol = svia_scr_read(ap, SCR_CONTROL);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(ap, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3;
@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */
- svia_scr_read(ap, SCR_STATUS);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
if (!online) {
/* tell EH to bail */
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1b5d81faa10..24344d0d057 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,20 +98,21 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 2288b55d916..d50b8238115 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -64,7 +64,6 @@ struct vdc_port {
u64 operations;
u32 vdisk_size;
u8 vdisk_type;
- u8 dev_no;
char disk_name[32];
@@ -703,7 +702,7 @@ static int probe_disk(struct vdc_port *port)
blk_queue_max_phys_segments(q, port->ring_cookies);
blk_queue_max_sectors(q, port->max_xfer_size);
g->major = vdc_major;
- g->first_minor = port->dev_no << PARTITION_SHIFT;
+ g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
strcpy(g->disk_name, port->disk_name);
g->fops = &vdc_fops;
@@ -747,21 +746,16 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
{
struct mdesc_handle *hp;
struct vdc_port *port;
- const u64 *port_id;
int err;
print_version();
hp = mdesc_grab();
- port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
err = -ENODEV;
- if (!port_id) {
- printk(KERN_ERR PFX "Port lacks id property.\n");
- goto err_out_release_mdesc;
- }
- if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
- printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+ if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+ printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+ vdev->dev_no);
goto err_out_release_mdesc;
}
@@ -772,16 +766,14 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
goto err_out_release_mdesc;
}
- port->dev_no = *port_id;
-
- if (port->dev_no >= 26)
+ if (vdev->dev_no >= 26)
snprintf(port->disk_name, sizeof(port->disk_name),
VDCBLK_NAME "%c%c",
- 'a' + (port->dev_no / 26) - 1,
- 'a' + (port->dev_no % 26));
+ 'a' + ((int)vdev->dev_no / 26) - 1,
+ 'a' + ((int)vdev->dev_no % 26));
else
snprintf(port->disk_name, sizeof(port->disk_name),
- VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+ VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -849,7 +841,7 @@ static struct vio_device_id vdc_port_match[] = {
},
{},
};
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
static struct vio_driver vdc_port_driver = {
.id_table = vdc_port_match,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 9e8f21410d2..c8dfd18bea4 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -185,7 +185,7 @@ config ESPSERIAL
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -241,7 +241,7 @@ config SYNCLINK
config SYNCLINKMP
tristate "SyncLink Multiport support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && PCI
help
Enable support for the SyncLink Multiport (2 or 4 ports)
serial adapter, running asynchronous and HDLC communications up
@@ -726,7 +726,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0be700f4e8f..ba0e74ad74b 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -29,6 +29,7 @@
#include <linux/bcd.h>
#include <linux/seq_file.h>
#include <linux/bitops.h>
+#include <linux/clocksource.h>
#include <asm/current.h>
#include <asm/uaccess.h>
@@ -51,8 +52,34 @@
#define HPET_RANGE_SIZE 1024 /* from HPET spec */
+#if BITS_PER_LONG == 64
+#define write_counter(V, MC) writeq(V, MC)
+#define read_counter(MC) readq(MC)
+#else
+#define write_counter(V, MC) writel(V, MC)
+#define read_counter(MC) readl(MC)
+#endif
+
static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+ return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+ .name = "hpet",
+ .rating = 250,
+ .read = read_hpet,
+ .mask = 0xffffffffffffffff,
+ .mult = 0, /*to be caluclated*/
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+
/* A lock for concurrent access by app and isr hpet activity. */
static DEFINE_SPINLOCK(hpet_lock);
/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +106,7 @@ struct hpets {
struct hpets *hp_next;
struct hpet __iomem *hp_hpet;
unsigned long hp_hpet_phys;
- struct time_interpolator *hp_interpolator;
+ struct clocksource *hp_clocksource;
unsigned long long hp_tick_freq;
unsigned long hp_delta;
unsigned int hp_ntimer;
@@ -94,13 +121,6 @@ static struct hpets *hpets;
#define HPET_PERIODIC 0x0004
#define HPET_SHARED_IRQ 0x0008
-#if BITS_PER_LONG == 64
-#define write_counter(V, MC) writeq(V, MC)
-#define read_counter(MC) readq(MC)
-#else
-#define write_counter(V, MC) writel(V, MC)
-#define read_counter(MC) readl(MC)
-#endif
#ifndef readq
static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +757,6 @@ static ctl_table dev_root[] = {
static struct ctl_table_header *sysctl_header;
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef CONFIG_TIME_INTERPOLATION
- struct time_interpolator *ti;
-
- ti = kzalloc(sizeof(*ti), GFP_KERNEL);
- if (!ti)
- return;
-
- ti->source = TIME_SOURCE_MMIO64;
- ti->shift = 10;
- ti->addr = &hpetp->hp_hpet->hpet_mc;
- ti->frequency = hpetp->hp_tick_freq;
- ti->drift = HPET_DRIFT;
- ti->mask = -1;
-
- hpetp->hp_interpolator = ti;
- register_time_interpolator(ti);
-#endif
-}
-
/*
* Adjustment for when arming the timer with
* initial conditions. That is, main counter
@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp)
}
hpetp->hp_delta = hpet_calibrate(hpetp);
- hpet_register_interpolator(hpetp);
+
+ if (!hpet_clocksource) {
+ hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+ CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+ clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+ clocksource_hpet.shift);
+ clocksource_register(&clocksource_hpet);
+ hpetp->hp_clocksource = &clocksource_hpet;
+ hpet_clocksource = &clocksource_hpet;
+ }
return 0;
}
@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device)
static int hpet_acpi_remove(struct acpi_device *device, int type)
{
- /* XXX need to unregister interpolator, dealloc mem, etc */
+ /* XXX need to unregister clocksource, dealloc mem, etc */
return -EINVAL;
}
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 22cf7aa56cc..30c3f54c766 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -86,12 +86,9 @@
#include <asm/hpet.h>
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
#include <linux/pci.h>
#include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
static unsigned long rtc_port;
static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@ static int __init rtc_init(void)
unsigned int year, ctrl;
char *guess = NULL;
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
#else
void *r;
#ifdef RTC_IRQ
@@ -944,7 +937,7 @@ static int __init rtc_init(void)
#endif
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@ static int __init rtc_init(void)
}
}
}
-#ifdef __sparc_v9__
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
- rtc_port = isa_dev->resource.start;
- rtc_irq = isa_dev->irq;
- goto found;
- }
- }
- }
-#endif
rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
@@ -1020,7 +1002,7 @@ no_irq:
#endif
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
if (misc_register(&rtc_dev)) {
#ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
remove_proc_entry ("driver/rtc", NULL);
misc_deregister(&rtc_dev);
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
#endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
}
module_init(rtc_init);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c585b4738f8..f1497cecffd 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c,
return cy_serial_driver;
}
-static int __init serial167_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
static struct console sercons = {
.name = "ttyS",
.write = serial167_console_write,
.device = serial167_console_device,
- .setup = serial167_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 4eba32b23b2..8677fc6a545 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -427,7 +427,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +435,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +465,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +473,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_binary_bios_measurements_ops = {
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bef6d886d4f..e122a0e87bb 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index)
return scc_driver;
}
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-
static struct console sercons = {
.name = "ttyS",
.write = scc_console_write,
.device = scc_console_device,
- .setup = scc_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 2f48ba32996..ad5cc5f6862 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -602,7 +602,7 @@ config ZVM_WATCHDOG
config SH_WDT
tristate "SuperH Watchdog"
- depends on SUPERH
+ depends on SUPERH && (CPU_SH3 || CPU_SH4)
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e1e9d9d6893..f0829b83e97 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
@@ -54,6 +55,7 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
*/
int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
/*
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 75b4d2a83dd..5fe75558662 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -471,37 +471,16 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
return 0;
}
-static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos)
-{
- struct list_head *node;
- loff_t i = 0;
-
- list_for_each(node, list)
- if (i++ == *pos)
- return node;
-
- return NULL;
-}
-
-static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos)
-{
- if (element->next == list)
- return NULL;
-
- ++(*pos);
- return element->next;
-}
-
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
- return list_get_nth_element(&input_dev_list, pos);
+ return seq_list_start(&input_dev_list, *pos);
}
static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- return list_get_next_element(&input_dev_list, v, pos);
+ return seq_list_next(v, &input_dev_list, pos);
}
static void input_devices_seq_stop(struct seq_file *seq, void *v)
@@ -592,13 +571,13 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
seq->private = (void *)(unsigned long)*pos;
- return list_get_nth_element(&input_handler_list, pos);
+ return seq_list_start(&input_handler_list, *pos);
}
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
seq->private = (void *)(unsigned long)(*pos + 1);
- return list_get_next_element(&input_handler_list, v, pos);
+ return seq_list_next(v, &input_handler_list, pos);
}
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 12db72d83ea..e2abe18e575 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -275,4 +275,11 @@ config JOYSTICK_XPAD_FF
---help---
Say Y here if you want to take advantage of xbox 360 rumble features.
+config JOYSTICK_XPAD_LEDS
+ bool "LED Support for Xbox360 controller 'BigX' LED"
+ depends on LEDS_CLASS && JOYSTICK_XPAD
+ ---help---
+ This option enables support for the LED which surrounds the Big X on
+ XBox 360 controller.
+
endif
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 244089c5265..28080395899 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -191,13 +191,18 @@ struct usb_xpad {
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct urb *irq_out; /* urb for interrupt out report */
unsigned char *odata; /* output data */
dma_addr_t odata_dma;
+ struct mutex odata_mutex;
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+ struct xpad_led *led;
#endif
- char phys[65]; /* physical device path */
+ char phys[64]; /* physical device path */
int dpad_mapping; /* map d-pad to buttons or to axes */
int xtype; /* type of xbox device */
@@ -349,7 +354,7 @@ exit:
__FUNCTION__, retval);
}
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out(struct urb *urb)
{
int retval;
@@ -376,29 +381,7 @@ exit:
__FUNCTION__, retval);
}
-static int xpad_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
-{
- struct usb_xpad *xpad = input_get_drvdata(dev);
-
- if (effect->type == FF_RUMBLE) {
- __u16 strong = effect->u.rumble.strong_magnitude;
- __u16 weak = effect->u.rumble.weak_magnitude;
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x08;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = strong / 256;
- xpad->odata[4] = weak / 256;
- xpad->odata[5] = 0x00;
- xpad->odata[6] = 0x00;
- xpad->odata[7] = 0x00;
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
- }
-
- return 0;
-}
-
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
{
struct usb_endpoint_descriptor *ep_irq_out;
int error = -ENOMEM;
@@ -411,6 +394,8 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
if (!xpad->odata)
goto fail1;
+ mutex_init(&xpad->odata_mutex);
+
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out)
goto fail2;
@@ -423,25 +408,19 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
xpad->irq_out->transfer_dma = xpad->odata_dma;
xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
-
- error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
- if (error)
- goto fail2;
-
return 0;
fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
fail1: return error;
}
-static void xpad_stop_ff(struct usb_xpad *xpad)
+static void xpad_stop_output(struct usb_xpad *xpad)
{
if (xpad->xtype == XTYPE_XBOX360)
usb_kill_urb(xpad->irq_out);
}
-static void xpad_deinit_ff(struct usb_xpad *xpad)
+static void xpad_deinit_output(struct usb_xpad *xpad)
{
if (xpad->xtype == XTYPE_XBOX360) {
usb_free_urb(xpad->irq_out);
@@ -449,13 +428,130 @@ static void xpad_deinit_ff(struct usb_xpad *xpad)
xpad->odata, xpad->odata_dma);
}
}
+#else
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_deinit_output(struct usb_xpad *xpad) {}
+static void xpad_stop_output(struct usb_xpad *xpad) {}
+#endif
+
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+static int xpad_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct usb_xpad *xpad = input_get_drvdata(dev);
+ if (effect->type == FF_RUMBLE) {
+ __u16 strong = effect->u.rumble.strong_magnitude;
+ __u16 weak = effect->u.rumble.weak_magnitude;
+ xpad->odata[0] = 0x00;
+ xpad->odata[1] = 0x08;
+ xpad->odata[2] = 0x00;
+ xpad->odata[3] = strong / 256;
+ xpad->odata[4] = weak / 256;
+ xpad->odata[5] = 0x00;
+ xpad->odata[6] = 0x00;
+ xpad->odata[7] = 0x00;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static int xpad_init_ff(struct usb_xpad *xpad)
+{
+ input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+ return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+ char name[16];
+ struct led_classdev led_cdev;
+ struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+ if (command >= 0 && command < 14) {
+ mutex_lock(&xpad->odata_mutex);
+ xpad->odata[0] = 0x01;
+ xpad->odata[1] = 0x03;
+ xpad->odata[2] = command;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ mutex_unlock(&xpad->odata_mutex);
+ }
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct xpad_led *xpad_led = container_of(led_cdev,
+ struct xpad_led, led_cdev);
+
+ xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+ static atomic_t led_seq = ATOMIC_INIT(0);
+ long led_no;
+ struct xpad_led *led;
+ struct led_classdev *led_cdev;
+ int error;
+
+ if (xpad->xtype != XTYPE_XBOX360)
+ return 0;
+
+ xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led_no = (long)atomic_inc_return(&led_seq) - 1;
+
+ snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+ led->xpad = xpad;
+
+ led_cdev = &led->led_cdev;
+ led_cdev->name = led->name;
+ led_cdev->brightness_set = xpad_led_set;
+
+ error = led_classdev_register(&xpad->udev->dev, led_cdev);
+ if (error) {
+ kfree(led);
+ xpad->led = NULL;
+ return error;
+ }
+
+ /*
+ * Light up the segment corresponding to controller number
+ */
+ xpad_send_led_command(xpad, (led_no % 4) + 2);
+
+ return 0;
+}
+
+static void xpad_led_disconnect(struct usb_xpad *xpad)
+{
+ struct xpad_led *xpad_led = xpad->led;
+
+ if (xpad_led) {
+ led_classdev_unregister(&xpad_led->led_cdev);
+ kfree(xpad_led->name);
+ }
+}
#else
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_stop_ff(struct usb_xpad *xpad) { }
-static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
+static void xpad_led_disconnect(struct usb_xpad *xpad) { }
#endif
+
static int xpad_open(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@ static void xpad_close(struct input_dev *dev)
struct usb_xpad *xpad = input_get_drvdata(dev);
usb_kill_urb(xpad->irq_in);
- xpad_stop_ff(xpad);
+ xpad_stop_output(xpad);
}
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
for (i = 0; xpad_abs_pad[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
- error = xpad_init_ff(intf, xpad);
+ error = xpad_init_output(intf, xpad);
if (error)
goto fail2;
+ error = xpad_init_ff(xpad);
+ if (error)
+ goto fail3;
+
+ error = xpad_led_probe(xpad);
+ if (error)
+ goto fail3;
+
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev,
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = input_register_device(xpad->dev);
if (error)
- goto fail3;
+ goto fail4;
usb_set_intfdata(intf, xpad);
return 0;
- fail3: usb_free_urb(xpad->irq_in);
+ fail4: usb_free_urb(xpad->irq_in);
+ fail3: xpad_deinit_output(xpad);
fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
fail1: input_free_device(input_dev);
kfree(xpad);
@@ -597,8 +702,9 @@ static void xpad_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
if (xpad) {
+ xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
- xpad_deinit_ff(xpad);
+ xpad_deinit_output(xpad);
usb_free_urb(xpad->irq_in);
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e3215267db1..2bea1b2c631 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -155,6 +155,8 @@ struct atp {
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int overflowwarn; /* overflow warning printed? */
int datalen; /* size of an USB urb transfer */
+ int idlecount; /* number of empty packets */
+ struct work_struct work;
};
#define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@ static inline int atp_is_geyser_3(struct atp *dev)
(productId == GEYSER4_JIS_PRODUCT_ID);
}
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+ char data[8];
+ int size;
+
+ size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_READ_REQUEST_ID,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode read request from device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+
+ /* Apply the mode switch */
+ data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+ size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode write request to device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+ struct atp *dev = container_of(work, struct atp, work);
+ struct usb_device *udev = dev->udev;
+
+ dev->idlecount = 0;
+ atp_geyser3_init(udev);
+}
+
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int *z, int *fingers)
{
@@ -439,8 +490,8 @@ static void atp_complete(struct urb* urb)
}
dev->x_old = x;
dev->y_old = y;
- }
- else if (!x && !y) {
+
+ } else if (!x && !y) {
dev->x_old = dev->y_old = -1;
input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +500,21 @@ static void atp_complete(struct urb* urb)
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
- }
- input_report_key(dev->input, BTN_LEFT,
- !!dev->data[dev->datalen - 1]);
+ /* Geyser 3 will continue to send packets continually after
+ the first touch unless reinitialised. Do so if it's been
+ idle for a while in order to avoid waking the kernel up
+ several hundred times a second */
+ if (atp_is_geyser_3(dev)) {
+ dev->idlecount++;
+ if (dev->idlecount == 10) {
+ dev->valid = 0;
+ schedule_work(&dev->work);
+ }
+ }
+ }
+ input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1);
input_sync(dev->input);
exit:
@@ -480,6 +541,7 @@ static void atp_close(struct input_dev *input)
struct atp *dev = input_get_drvdata(input);
usb_kill_urb(dev->urb);
+ cancel_work_sync(&dev->work);
dev->open = 0;
}
@@ -528,40 +590,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
dev->datalen = 81;
if (atp_is_geyser_3(dev)) {
- /*
- * By default Geyser 3 device sends standard USB HID mouse
- * packets (Report ID 2). This code changes device mode, so it
- * sends raw sensor reports (Report ID 5).
- */
- char data[8];
- int size;
-
- size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_READ_REQUEST_ID,
- USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
- if (size != 8) {
- err("Could not do mode read request from device"
- " (Geyser 3 mode)");
+ /* switch to raw sensor mode */
+ if (atp_geyser3_init(udev))
goto err_free_devs;
- }
-
- /* Apply the mode switch */
- data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
- size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
- if (size != 8) {
- err("Could not do mode write request to device"
- " (Geyser 3 mode)");
- goto err_free_devs;
- }
printk("appletouch Geyser 3 inited.\n");
}
@@ -636,6 +668,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
/* save our data pointer in this interface device */
usb_set_intfdata(iface, dev);
+ INIT_WORK(&dev->work, atp_reinit);
+
return 0;
err_free_buffer:
@@ -669,14 +703,17 @@ static void atp_disconnect(struct usb_interface *iface)
static int atp_suspend(struct usb_interface *iface, pm_message_t message)
{
struct atp *dev = usb_get_intfdata(iface);
+
usb_kill_urb(dev->urb);
dev->valid = 0;
+
return 0;
}
static int atp_resume(struct usb_interface *iface)
{
struct atp *dev = usb_get_intfdata(iface);
+
if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
return -EIO;
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 1740cadd959..91109b49fde 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -109,7 +109,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
struct lifebook_data *priv = psmouse->private;
struct input_dev *dev1 = psmouse->dev;
- struct input_dev *dev2 = priv->dev2;
+ struct input_dev *dev2 = priv ? priv->dev2 : NULL;
unsigned char *packet = psmouse->packet;
int relative_packet = packet[0] & 0x08;
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 4fca1e7f267..702a526cf45 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -366,6 +366,7 @@ static void i8042_pnp_exit(void)
static int __init i8042_pnp_init(void)
{
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+ int pnp_data_busted = 0;
int err;
if (i8042_nopnp) {
@@ -413,27 +414,48 @@ static int __init i8042_pnp_init(void)
#endif
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
- i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
- printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+ i8042_pnp_data_reg != i8042_data_reg) ||
+ !i8042_pnp_data_reg) {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller has invalid data port %#x; "
+ "using default %#x\n",
i8042_pnp_data_reg, i8042_data_reg);
i8042_pnp_data_reg = i8042_data_reg;
+ pnp_data_busted = 1;
}
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
- i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
- printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+ i8042_pnp_command_reg != i8042_command_reg) ||
+ !i8042_pnp_command_reg) {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller has invalid command port %#x; "
+ "using default %#x\n",
i8042_pnp_command_reg, i8042_command_reg);
i8042_pnp_command_reg = i8042_command_reg;
+ pnp_data_busted = 1;
}
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
- printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
+ printk(KERN_WARNING
+ "PNP: PS/2 controller doesn't have KBD irq; "
+ "using default %d\n", i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq;
+ pnp_data_busted = 1;
}
if (!i8042_noaux && !i8042_pnp_aux_irq) {
- printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
- i8042_pnp_aux_irq = i8042_aux_irq;
+ if (!pnp_data_busted && i8042_pnp_kbd_irq) {
+ printk(KERN_WARNING
+ "PNP: PS/2 appears to have AUX port disabled, "
+ "if this is incorrect please boot with "
+ "i8042.nopnp\n");
+ i8042_noaux = 1;
+ } else {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller doesn't have AUX irq; "
+ "using default %d\n", i8042_aux_irq);
+ i8042_pnp_aux_irq = i8042_aux_irq;
+ }
}
i8042_data_reg = i8042_pnp_data_reg;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 69371779806..f929fcdbae2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -54,6 +54,19 @@ config TOUCHSCREEN_CORGI
To compile this driver as a module, choose M here: the
module will be called corgi_ts.
+config TOUCHSCREEN_FUJITSU
+ tristate "Fujitsu serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have the Fujitsu touchscreen (such as one
+ installed in Lifebook P series laptop) connected to your
+ system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fujitsu-ts.
+
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 2f86d6ad06d..5de8933c499 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1c9069cd3ba..96581d08774 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -95,7 +95,7 @@ struct ads7846 {
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
- struct spi_transfer xfer[10];
+ struct spi_transfer xfer[18];
struct spi_message msg[5];
struct spi_message *last_msg;
int msg_idx;
@@ -107,6 +107,8 @@ struct ads7846 {
u16 debounce_tol;
u16 debounce_rep;
+ u16 penirq_recheck_delay_usecs;
+
spinlock_t lock;
struct hrtimer timer;
unsigned pendown:1; /* P: lock */
@@ -553,6 +555,15 @@ static void ads7846_rx(void *ads)
return;
}
+ /* Maybe check the pendown state before reporting. This discards
+ * false readings when the pen is lifted.
+ */
+ if (ts->penirq_recheck_delay_usecs) {
+ udelay(ts->penirq_recheck_delay_usecs);
+ if (!ts->get_pendown_state())
+ Rt = 0;
+ }
+
/* NOTE: We can't rely on the pressure to determine the pen down
* state, even this controller has a pressure sensor. The pressure
* value can fluctuate for quite a while after lifting the pen and
@@ -896,6 +907,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
+ if (pdata->penirq_recheck_delay_usecs)
+ ts->penirq_recheck_delay_usecs =
+ pdata->penirq_recheck_delay_usecs;
+
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
input_dev->name = "ADS784x Touchscreen";
@@ -936,6 +951,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* the first sample after switching drivers can be low quality;
+ * optionally discard it, using a second one after the signals
+ * have had enough time to stabilize.
+ */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_y;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.y;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -954,6 +987,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_x;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.x;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -973,6 +1021,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_z1;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.z1;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -990,6 +1053,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_z2;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.z2;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
}
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644
index 00000000000..daf7a4afc93
--- /dev/null
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[FUJITSU_LENGTH];
+ char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct fujitsu *fujitsu = serio_get_drvdata(serio);
+ struct input_dev *dev = fujitsu->dev;
+
+ if (fujitsu->idx == 0) {
+ /* resync skip until start of frame */
+ if ((data & 0xf0) != 0x80)
+ return IRQ_HANDLED;
+ } else {
+ /* resync skip garbage */
+ if (data & 0x80) {
+ fujitsu->idx = 0;
+ return IRQ_HANDLED;
+ }
+ }
+
+ fujitsu->data[fujitsu->idx++] = data;
+ if (fujitsu->idx == FUJITSU_LENGTH) {
+ input_report_abs(dev, ABS_X,
+ (fujitsu->data[2] << 7) | fujitsu->data[1]);
+ input_report_abs(dev, ABS_Y,
+ (fujitsu->data[4] << 7) | fujitsu->data[3]);
+ input_report_key(dev, BTN_TOUCH,
+ (fujitsu->data[0] & 0x03) != 2);
+ input_sync(dev);
+ fujitsu->idx = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+ struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+ input_get_device(fujitsu->dev);
+ input_unregister_device(fujitsu->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(fujitsu->dev);
+ kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct fujitsu *fujitsu;
+ struct input_dev *input_dev;
+ int err;
+
+ fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!fujitsu || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ fujitsu->serio = serio;
+ fujitsu->dev = input_dev;
+ snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+ "%s/input0", serio->phys);
+
+ input_dev->name = "Fujitsu Serial Touchscreen";
+ input_dev->phys = fujitsu->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_FUJITSU;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0100;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+ serio_set_drvdata(serio, fujitsu);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(fujitsu->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3:
+ serio_close(serio);
+ fail2:
+ serio_set_drvdata(serio, NULL);
+ fail1:
+ input_free_device(input_dev);
+ kfree(fujitsu);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_FUJITSU,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+ .driver = {
+ .name = "fujitsu_ts",
+ },
+ .description = DRIVER_DESC,
+ .id_table = fujitsu_serio_ids,
+ .interrupt = fujitsu_interrupt,
+ .connect = fujitsu_connect,
+ .disconnect = fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+ return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+ serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index a7c5e6bee03..3ac9cbce336 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -121,7 +121,7 @@ struct kvm_pte_chain {
* bits 4:7 - page table level for this shadow (1-4)
* bits 8:9 - page table quadrant for 2-level guests
* bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- * bits 17:18 - "access" - the user and writable bits of a huge page pde
+ * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
*/
union kvm_mmu_page_role {
unsigned word;
@@ -131,7 +131,7 @@ union kvm_mmu_page_role {
unsigned quadrant : 2;
unsigned pad_for_nice_hex_output : 6;
unsigned metaphysical : 1;
- unsigned hugepage_access : 2;
+ unsigned hugepage_access : 3;
};
};
@@ -535,8 +535,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
int kvm_mmu_setup(struct kvm_vcpu *vcpu);
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1b206f197c6..bcbe6835beb 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -238,23 +238,6 @@ static void vcpu_load(struct kvm_vcpu *vcpu)
kvm_arch_ops->vcpu_load(vcpu);
}
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
- struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
- mutex_lock(&vcpu->mutex);
- if (!vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return NULL;
- }
- kvm_arch_ops->vcpu_load(vcpu);
- return vcpu;
-}
-
static void vcpu_put(struct kvm_vcpu *vcpu)
{
kvm_arch_ops->vcpu_put(vcpu);
@@ -663,13 +646,6 @@ void fx_init(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(fx_init);
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_slot_remove_write_access(vcpu, slot);
- spin_unlock(&vcpu->kvm->lock);
-}
-
/*
* Allocate some memory and give it an address in the guest physical address
* space.
@@ -792,19 +768,10 @@ raced:
*memslot = new;
++kvm->memory_config_version;
- spin_unlock(&kvm->lock);
-
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
+ kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+ kvm_flush_remote_tlbs(kvm);
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
- do_remove_write_access(vcpu, mem->slot);
- kvm_mmu_reset_context(vcpu);
- vcpu_put(vcpu);
- }
+ spin_unlock(&kvm->lock);
kvm_free_physmem_slot(&old, &new);
return 0;
@@ -826,7 +793,6 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot;
int r, i;
int n;
- int cleared;
unsigned long any = 0;
spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
- if (any) {
- cleared = 0;
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
-
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (!cleared) {
- do_remove_write_access(vcpu, log->slot);
- memset(memslot->dirty_bitmap, 0, n);
- cleared = 1;
- }
- kvm_arch_ops->tlb_flush(vcpu);
- vcpu_put(vcpu);
- }
- }
+ spin_lock(&kvm->lock);
+ kvm_mmu_slot_remove_write_access(kvm, log->slot);
+ kvm_flush_remote_tlbs(kvm);
+ memset(memslot->dirty_bitmap, 0, n);
+ spin_unlock(&kvm->lock);
r = 0;
@@ -920,13 +874,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
break;
kvm->naliases = n;
- spin_unlock(&kvm->lock);
+ kvm_mmu_zap_all(kvm);
- vcpu_load(&kvm->vcpus[0]);
- spin_lock(&kvm->lock);
- kvm_mmu_zap_all(&kvm->vcpus[0]);
spin_unlock(&kvm->lock);
- vcpu_put(&kvm->vcpus[0]);
return 0;
@@ -1567,7 +1517,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
}
@@ -1645,7 +1595,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
return kvm_arch_ops->set_msr(vcpu, msr_index, data);
}
@@ -2183,7 +2133,7 @@ static __init void kvm_init_msr_list(void)
*/
static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
{
- return set_msr(vcpu, index, *data);
+ return kvm_set_msr(vcpu, index, *data);
}
/*
@@ -2667,7 +2617,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(vcpu, argp, get_msr, 1);
+ r = msr_io(vcpu, argp, kvm_get_msr, 1);
break;
case KVM_SET_MSRS:
r = msr_io(vcpu, argp, do_set_msr, 0);
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 1199d3f32ac..d99d2fe53dc 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -154,7 +154,6 @@ struct kvm_rmap_desc {
static struct kmem_cache *pte_chain_cache;
static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
static struct kmem_cache *mmu_page_header_cache;
static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
kfree(mc->objects[--mc->nobjs]);
}
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+ int min, gfp_t gfp_flags)
+{
+ struct page *page;
+
+ if (cache->nobjs >= min)
+ return 0;
+ while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+ page = alloc_page(gfp_flags);
+ if (!page)
+ return -ENOMEM;
+ set_page_private(page, 0);
+ cache->objects[cache->nobjs++] = page_address(page);
+ }
+ return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+ while (mc->nobjs)
+ __free_page(mc->objects[--mc->nobjs]);
+}
+
static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
{
int r;
@@ -237,8 +259,7 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
rmap_desc_cache, 1, gfp_flags);
if (r)
goto out;
- r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
- mmu_page_cache, 4, gfp_flags);
+ r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -266,7 +287,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
- mmu_free_memory_cache(&vcpu->mmu_page_cache);
+ mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
}
@@ -281,24 +302,15 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
return p;
}
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
- if (mc->nobjs < KVM_NR_MEM_OBJS)
- mc->objects[mc->nobjs++] = obj;
- else
- kfree(obj);
-}
-
static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
{
return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
sizeof(struct kvm_pte_chain));
}
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
- struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
{
- mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+ kfree(pc);
}
static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +319,9 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
sizeof(struct kvm_rmap_desc));
}
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
- struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
{
- mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+ kfree(rd);
}
/*
@@ -355,8 +366,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
}
}
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
- struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
struct kvm_rmap_desc *desc,
int i,
struct kvm_rmap_desc *prev_desc)
@@ -376,10 +386,10 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
prev_desc->more = desc->more;
else
set_page_private(page,(unsigned long)desc->more | 1);
- mmu_free_rmap_desc(vcpu, desc);
+ mmu_free_rmap_desc(desc);
}
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
{
struct page *page;
struct kvm_rmap_desc *desc;
@@ -407,7 +417,7 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
while (desc) {
for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
if (desc->shadow_ptes[i] == spte) {
- rmap_desc_remove_entry(vcpu, page,
+ rmap_desc_remove_entry(page,
desc, i,
prev_desc);
return;
@@ -442,7 +452,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
BUG_ON(!(*spte & PT_PRESENT_MASK));
BUG_ON(!(*spte & PT_WRITABLE_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
- rmap_remove(vcpu, spte);
+ rmap_remove(spte);
set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
kvm_flush_remote_tlbs(vcpu->kvm);
}
@@ -464,14 +474,14 @@ static int is_empty_shadow_page(u64 *spt)
}
#endif
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
struct kvm_mmu_page *page_head)
{
ASSERT(is_empty_shadow_page(page_head->spt));
list_del(&page_head->link);
- mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
- mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
- ++vcpu->kvm->n_free_mmu_pages;
+ __free_page(virt_to_page(page_head->spt));
+ kfree(page_head);
+ ++kvm->n_free_mmu_pages;
}
static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +547,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[0] = parent_pte;
}
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
u64 *parent_pte)
{
struct kvm_pte_chain *pte_chain;
@@ -565,7 +574,7 @@ static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[i] = NULL;
if (i == 0) {
hlist_del(&pte_chain->link);
- mmu_free_pte_chain(vcpu, pte_chain);
+ mmu_free_pte_chain(pte_chain);
if (hlist_empty(&page->parent_ptes)) {
page->multimapped = 0;
page->parent_pte = NULL;
@@ -643,7 +652,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
return page;
}
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
struct kvm_mmu_page *page)
{
unsigned i;
@@ -655,10 +664,10 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
if (page->role.level == PT_PAGE_TABLE_LEVEL) {
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
if (pt[i] & PT_PRESENT_MASK)
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] = 0;
}
- kvm_flush_remote_tlbs(vcpu->kvm);
+ kvm_flush_remote_tlbs(kvm);
return;
}
@@ -669,19 +678,18 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
if (!(ent & PT_PRESENT_MASK))
continue;
ent &= PT64_BASE_ADDR_MASK;
- mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+ mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
}
- kvm_flush_remote_tlbs(vcpu->kvm);
+ kvm_flush_remote_tlbs(kvm);
}
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
u64 *parent_pte)
{
- mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+ mmu_page_remove_parent_pte(page, parent_pte);
}
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
struct kvm_mmu_page *page)
{
u64 *parent_pte;
@@ -697,15 +705,15 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
parent_pte = chain->parent_ptes[0];
}
BUG_ON(!parent_pte);
- kvm_mmu_put_page(vcpu, page, parent_pte);
+ kvm_mmu_put_page(page, parent_pte);
set_shadow_pte(parent_pte, 0);
}
- kvm_mmu_page_unlink_children(vcpu, page);
+ kvm_mmu_page_unlink_children(kvm, page);
if (!page->root_count) {
hlist_del(&page->hash_link);
- kvm_mmu_free_page(vcpu, page);
+ kvm_mmu_free_page(kvm, page);
} else
- list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+ list_move(&page->link, &kvm->active_mmu_pages);
}
static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +732,7 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
if (page->gfn == gfn && !page->role.metaphysical) {
pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
r = 1;
}
return r;
@@ -737,7 +745,7 @@ static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
pgprintk("%s: zap %lx %x\n",
__FUNCTION__, gfn, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
}
@@ -1089,10 +1097,10 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_present_pte(pte)) {
if (page->role.level == PT_PAGE_TABLE_LEVEL)
- rmap_remove(vcpu, spte);
+ rmap_remove(spte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
- mmu_page_remove_parent_pte(vcpu, child, spte);
+ mmu_page_remove_parent_pte(child, spte);
}
}
*spte = 0;
@@ -1161,7 +1169,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
*/
pgprintk("misaligned: gpa %llx bytes %d role %x\n",
gpa, bytes, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
continue;
}
page_offset = offset;
@@ -1207,7 +1215,7 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
page = container_of(vcpu->kvm->active_mmu_pages.prev,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
}
EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
@@ -1219,7 +1227,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
page = container_of(vcpu->kvm->active_mmu_pages.next,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
free_page((unsigned long)vcpu->mmu.pae_root);
}
@@ -1277,9 +1285,8 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
mmu_free_memory_caches(vcpu);
}
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
{
- struct kvm *kvm = vcpu->kvm;
struct kvm_mmu_page *page;
list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1300,20 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
/* avoid RMW */
if (pt[i] & PT_WRITABLE_MASK) {
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] &= ~PT_WRITABLE_MASK;
}
}
}
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
{
- destroy_kvm_mmu(vcpu);
-
- while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
- struct kvm_mmu_page *page;
+ struct kvm_mmu_page *page, *node;
- page = container_of(vcpu->kvm->active_mmu_pages.next,
- struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
- }
+ list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+ kvm_mmu_zap_page(kvm, page);
- mmu_free_memory_caches(vcpu);
- kvm_flush_remote_tlbs(vcpu->kvm);
- init_kvm_mmu(vcpu);
+ kvm_flush_remote_tlbs(kvm);
}
void kvm_mmu_module_exit(void)
@@ -1322,8 +1322,6 @@ void kvm_mmu_module_exit(void)
kmem_cache_destroy(pte_chain_cache);
if (rmap_desc_cache)
kmem_cache_destroy(rmap_desc_cache);
- if (mmu_page_cache)
- kmem_cache_destroy(mmu_page_cache);
if (mmu_page_header_cache)
kmem_cache_destroy(mmu_page_header_cache);
}
@@ -1341,12 +1339,6 @@ int kvm_mmu_module_init(void)
if (!rmap_desc_cache)
goto nomem;
- mmu_page_cache = kmem_cache_create("kvm_mmu_page",
- PAGE_SIZE,
- PAGE_SIZE, 0, NULL);
- if (!mmu_page_cache)
- goto nomem;
-
mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
sizeof(struct kvm_mmu_page),
0, 0, NULL);
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index a7c5cb0319e..4b5391c717f 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -366,6 +366,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
metaphysical = 1;
hugepage_access = *guest_ent;
hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+ if (*guest_ent & PT64_NX_MASK)
+ hugepage_access |= (1 << 2);
hugepage_access >>= PT_WRITABLE_SHIFT;
table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index f60012d6261..1b800fc0034 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -163,7 +163,7 @@ static u16 twobyte_table[256] = {
ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
unsigned long modrm_ea;
int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
int no_wb = 0;
+ u64 msr_data;
/* Shadow copy of register state. Committed on successful emulation. */
unsigned long _regs[NR_VCPU_REGS];
@@ -1344,6 +1345,29 @@ twobyte_special_insn:
goto cannot_emulate;
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
break;
+ case 0x30:
+ /* wrmsr */
+ msr_data = (u32)_regs[VCPU_REGS_RAX]
+ | ((u64)_regs[VCPU_REGS_RDX] << 32);
+ rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
+ case 0x32:
+ /* rdmsr */
+ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ } else {
+ _regs[VCPU_REGS_RAX] = (u32)msr_data;
+ _regs[VCPU_REGS_RDX] = msr_data >> 32;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
case 0xc7: /* Grp9 (cmpxchg8b) */
{
u64 old, new;
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index d9de5bbc613..bee029bb2c7 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -38,12 +38,12 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
ss = lg->regs->ss;
}
- /* We use IF bit in eflags to indicate whether irqs were disabled
- (it's always 0, since irqs are enabled when guest is running). */
+ /* We use IF bit in eflags to indicate whether irqs were enabled
+ (it's always 1, since irqs are enabled when guest is running). */
eflags = lg->regs->eflags;
- if (get_user(irq_enable, &lg->lguest_data->irq_enabled))
- irq_enable = 0;
- eflags |= (irq_enable & X86_EFLAGS_IF);
+ if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+ && !(irq_enable & X86_EFLAGS_IF))
+ eflags &= ~X86_EFLAGS_IF;
push_guest_stack(lg, &gstack, eflags);
push_guest_stack(lg, &gstack, lg->regs->cs);
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
index 06bdba2337e..c8eb7926699 100644
--- a/drivers/lguest/io.c
+++ b/drivers/lguest/io.c
@@ -187,7 +187,7 @@ static u32 copy_data(struct lguest *srclg,
/* FIXME: This is not completely portable, since
archs do different things for copy_to_user_page. */
if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
- (void *__user)src->addr[si], len) != 0) {
+ (void __user *)src->addr[si], len) != 0) {
kill_guest(srclg, "bad address in sending DMA");
totlen = 0;
break;
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
index b9a58b78c99..434fea1e82f 100644
--- a/drivers/lguest/lguest.c
+++ b/drivers/lguest/lguest.c
@@ -39,7 +39,6 @@
#include <asm/e820.h>
#include <asm/mce.h>
#include <asm/io.h>
-//#include <asm/sched-clock.h>
/* Declarations for definitions in lguest_guest.S */
extern char lguest_noirq_start[], lguest_noirq_end[];
@@ -57,6 +56,7 @@ struct lguest_data lguest_data = {
.blocked_interrupts = { 1 }, /* Block timer interrupts */
};
struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
static enum paravirt_lazy_mode lazy_mode;
static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
@@ -363,6 +363,11 @@ static struct clocksource lguest_clock = {
.read = lguest_clock_read,
};
+static unsigned long long lguest_sched_clock(void)
+{
+ return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
/* We also need a "struct clock_event_device": Linux asks us to set it to go
* off some time in the future. Actually, James Morris figured all this out, I
* just applied the patch. */
@@ -439,6 +444,7 @@ static void lguest_time_init(void)
lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8;
lguest_clock.mask = CLOCKSOURCE_MASK(32);
}
+ clock_base = lguest_clock_read();
clocksource_register(&lguest_clock);
/* We can't set cpumask in the initializer: damn C limitations! */
@@ -584,6 +590,7 @@ __init void lguest_init(void *boot)
paravirt_ops.time_init = lguest_time_init;
paravirt_ops.set_lazy_mode = lguest_lazy_mode;
paravirt_ops.wbinvd = lguest_wbinvd;
+ paravirt_ops.sched_clock = lguest_sched_clock;
hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
index 00046c57b5b..a3dbf22ee36 100644
--- a/drivers/lguest/lguest_asm.S
+++ b/drivers/lguest/lguest_asm.S
@@ -2,9 +2,7 @@
#include <linux/lguest.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
-
-/* FIXME: Once asm/processor-flags.h goes in, include that */
-#define X86_EFLAGS_IF 0x00000200
+#include <asm/processor-flags.h>
/*
* This is where we begin: we have a magic signature which the launcher looks
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c8dfdb30291..d90ee145eff 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -493,12 +493,12 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
if (frombio)
tx = async_memcpy(page, bio_page, page_offset,
b_offset, clen,
- ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+ ASYNC_TX_DEP_ACK,
tx, NULL, NULL);
else
tx = async_memcpy(bio_page, page, b_offset,
page_offset, clen,
- ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+ ASYNC_TX_DEP_ACK,
tx, NULL, NULL);
}
if (clen < len) /* hit end of page */
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fe447a06e24..a3292e955aa 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -345,8 +345,8 @@ void ir_rc5_timer_end(unsigned long data)
}
/* Set/reset key-up timer */
- timeout = current_jiffies + (500 + ir->rc5_key_timeout
- * HZ) / 1000;
+ timeout = current_jiffies +
+ msecs_to_jiffies(ir->rc5_key_timeout);
mod_timer(&ir->timer_keyup, timeout);
/* Save code for repeat test */
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 2cee9e3bd29..8178832d14a 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2267,7 +2267,7 @@ static int frontend_init(struct av7110 *av7110)
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index ce940b1b787..f0a67e93d7f 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -63,7 +63,7 @@ struct rt_device
static void sleep_delay(long n)
{
/* Sleep nicely for 'n' uS */
- int d=n/(1000000/HZ);
+ int d=n/msecs_to_jiffies(1000);
if(!d)
udelay(n);
else
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8cf2e9df5c8..34e317ced5a 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -329,7 +329,7 @@ cadet_handler(unsigned long data)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
@@ -349,7 +349,7 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
if(rdsin==rdsout) {
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 4db05b2b1b6..99a32313133 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -94,7 +94,6 @@ struct gemtek_pci_card {
u32 iobase;
u32 length;
- u16 model;
u32 current_frequency;
u8 mute;
@@ -413,8 +412,6 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
goto err_pci;
}
- pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
pci_set_drvdata( pci_dev, card );
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 2e4cf1efdd2..b767b098d14 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -257,7 +257,7 @@ static int bt866_write(struct bt866 *encoder,
printk(KERN_WARNING "%s: I/O error #%d "
"(write 0x%02x/0x%02x)\n",
encoder->i2c->name, err, encoder->addr, subaddr);
- schedule_timeout_interruptible(HZ/10);
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
}
if (err == 3) {
printk(KERN_WARNING "%s: giving up\n",
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 2aea09c7209..387cb2122d4 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -4209,7 +4209,7 @@ static int tea5757_read(struct bttv *btv)
bus_low(btv,btv->mbox_clk);
udelay(10);
- timeout= jiffies + HZ;
+ timeout= jiffies + msecs_to_jiffies(1000);
/* wait for DATA line to go low; error if it doesn't */
while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 94a13d0ee61..4201552bc3c 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -153,7 +153,7 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
- ir->timer.expires = jiffies + HZ;
+ ir->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index bd85f6d0fbe..5b25faca150 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -284,8 +284,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE (HZ) /* one second */
+#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */
struct bttv_pll_info {
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 925ff17efbb..f76c6a6c376 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -95,7 +95,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready1(qcam) == value)
return 0;
@@ -120,7 +120,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready2(qcam) == value)
return 0;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 98fa35421bd..06b233a7b20 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1881,8 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
mutex_unlock(&core->lock);
/* start tvaudio thread */
- if (core->tuner_type != TUNER_ABSENT)
+ if (core->tuner_type != TUNER_ABSENT) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+ if (IS_ERR(core->kthread)) {
+ err = PTR_ERR(core->kthread);
+ printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
+ err);
+ }
+ }
return 0;
fail_unreg:
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c4f656ec46b..809126866a3 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -259,7 +259,7 @@ struct cx88_subid {
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
/* buffer for one video frame */
struct cx88_buffer {
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 1aaeaa02f15..e43beb2c9cb 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ select I2C_ALGOBIT
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -16,11 +17,11 @@ config VIDEO_IVTV
select VIDEO_UPD64031A
select VIDEO_UPD64083
---help---
- This is a video4linux driver for Conexant cx23416 or cx23416 based
+ This is a video4linux driver for Conexant cx23416 or cx23415 based
PCI personal video recorder devices.
This is used in devices such as the Hauppauge PVR-150/250/350/500
- cards.
+ cards. There is a driver homepage at <http://www.ivtvdriver.org>.
To compile this driver as a module, choose M here: the
module will be called ivtv.
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 4c93466a89e..d73d433a4ff 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -56,7 +56,6 @@
#include "ivtv-gpio.h"
#include "ivtv-yuv.h"
-#include <linux/vermagic.h>
#include <media/tveeprom.h>
#include <media/v4l2-chip-ident.h>
@@ -276,9 +275,10 @@ int ivtv_waitq(wait_queue_head_t *waitq)
}
/* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
{
int ret;
+ int timeout = msecs_to_jiffies(msecs);
do {
set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -427,7 +427,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
if (itv->options.newi2c) {
- IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+ IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
exit_ivtv_i2c(itv);
init_ivtv_i2c(itv);
}
@@ -951,7 +951,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
/* Make sure we've got a place for this card */
if (ivtv_cards_active == IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n",
+ printk(KERN_ERR "ivtv: Maximum number of cards detected (%d)\n",
ivtv_cards_active);
spin_unlock(&ivtv_cards_lock);
return -ENOMEM;
@@ -966,9 +966,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
itv->dev = dev;
itv->num = ivtv_cards_active++;
snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
- if (itv->num) {
- printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n");
- }
+ IVTV_INFO("Initializing card #%d\n", itv->num);
spin_unlock(&ivtv_cards_lock);
@@ -1215,7 +1213,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
if (itv->has_cx23415)
ivtv_set_osd_alpha(itv);
- IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+ IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
@@ -1248,15 +1246,15 @@ static void ivtv_remove(struct pci_dev *pci_dev)
{
struct ivtv *itv = pci_get_drvdata(pci_dev);
- IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+ IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
/* Stop all captures */
- IVTV_DEBUG_INFO(" Stopping all streams.\n");
+ IVTV_DEBUG_INFO("Stopping all streams\n");
if (atomic_read(&itv->capturing) > 0)
ivtv_stop_all_captures(itv);
/* Stop all decoding */
- IVTV_DEBUG_INFO(" Stopping decoding.\n");
+ IVTV_DEBUG_INFO("Stopping decoding\n");
if (atomic_read(&itv->decoding) > 0) {
int type;
@@ -1269,30 +1267,30 @@ static void ivtv_remove(struct pci_dev *pci_dev)
}
/* Interrupts */
- IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+ IVTV_DEBUG_INFO("Disabling interrupts\n");
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
/* Stop all Work Queues */
- IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+ IVTV_DEBUG_INFO("Stop Work Queues\n");
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+ IVTV_DEBUG_INFO("Stopping Firmware\n");
ivtv_halt_firmware(itv);
- IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+ IVTV_DEBUG_INFO("Unregistering v4l devices\n");
ivtv_streams_cleanup(itv);
- IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+ IVTV_DEBUG_INFO("Freeing dma resources\n");
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
- IVTV_DEBUG_INFO(" Releasing irq.\n");
+ IVTV_DEBUG_INFO(" Releasing irq\n");
free_irq(itv->dev->irq, (void *)itv);
ivtv_iounmap(itv);
- IVTV_DEBUG_INFO(" Releasing mem.\n");
+ IVTV_DEBUG_INFO(" Releasing mem\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
@@ -1313,28 +1311,27 @@ static struct pci_driver ivtv_pci_driver = {
static int module_start(void)
{
- printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n");
- printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+ printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
memset(ivtv_cards, 0, sizeof(ivtv_cards));
/* Validate parameters */
if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n",
+ printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
IVTV_MAX_CARDS - 1);
return -1;
}
if (ivtv_debug < 0 || ivtv_debug > 1023) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 1023!\n");
+ printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
printk(KERN_ERR "ivtv: Error detecting PCI card\n");
return -ENODEV;
}
- printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n");
+ printk(KERN_INFO "ivtv: End initialization\n");
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 6c1a85f1ee1..91b588d261a 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -848,7 +848,7 @@ int ivtv_set_output_mode(struct ivtv *itv, int mode);
struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
/* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
/* Wait on queue, returns -EINTR if interrupted */
int ivtv_waitq(wait_queue_head_t *waitq);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index ee7e884e9c4..8e97a938398 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -218,7 +218,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* Process pending program info updates and pending VBI data */
ivtv_update_pgm_info(itv);
- if (jiffies - itv->dualwatch_jiffies > HZ) {
+ if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
itv->dualwatch_jiffies = jiffies;
ivtv_dualwatch(itv);
}
@@ -832,7 +832,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
if (itv == NULL) {
/* Couldn't find a device registered
on that minor, shouldn't happen! */
- printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+ printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor);
return -ENXIO;
}
@@ -924,7 +924,7 @@ void ivtv_unmute(struct ivtv *itv)
if (atomic_read(&itv->capturing) == 0)
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
if (atomic_read(&itv->capturing)) {
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index 2b6208a6a10..d0feabf9308 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -36,7 +36,7 @@
#define IVTV_CMD_SPU_STOP 0x00000001
#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
-#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME 600
#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg"
#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024)
@@ -61,7 +61,7 @@ retry:
the wrong file was sometimes loaded. So we check filesizes to
see if at least the right-sized file was loaded. If not, then we
retry. */
- IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+ IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
release_firmware(fw);
retries--;
goto retry;
@@ -73,11 +73,11 @@ retry:
src++;
}
release_firmware(fw);
- IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
return size;
}
- IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
- IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+ IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
return -ENOMEM;
}
@@ -89,7 +89,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
if (itv->enc_mbox.mbox)
ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -113,7 +113,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
IVTV_DEBUG_INFO("Stopping SPU\n");
write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -129,9 +129,8 @@ void ivtv_halt_firmware(struct ivtv *itv)
write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
}
- IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
- (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
- ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+ IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+ ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
}
void ivtv_firmware_versions(struct ivtv *itv)
@@ -204,12 +203,12 @@ int ivtv_firmware_init(struct ivtv *itv)
/* start firmware */
write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
if (itv->has_cx23415)
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
else
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
/* find mailboxes and ping firmware */
itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -264,7 +263,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
IVTV_DECODE_INIT_MPEG_FILENAME);
} else {
ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
}
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 676418cbaaa..6a5a7aa6697 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -130,7 +130,7 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
return -EINVAL;
- IVTV_INFO("Resetting tuner.\n");
+ IVTV_INFO("Resetting tuner\n");
curout = read_reg(IVTV_REG_GPIO_OUT);
curdir = read_reg(IVTV_REG_GPIO_DIR);
curdir |= (1 << 12); /* GPIO bit 12 */
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 50624c6a62a..b3557435456 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -144,7 +144,7 @@ static int attach_inform(struct i2c_client *client)
}
}
if (i == I2C_CLIENTS_MAX) {
- IVTV_ERR("insufficient room for new I2C client!\n");
+ IVTV_ERR("Insufficient room for new I2C client\n");
}
return 0;
}
@@ -236,7 +236,7 @@ static int ivtv_ack(struct ivtv *itv)
int ret = 0;
if (ivtv_getscl(itv) == 1) {
- IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+ IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +263,7 @@ static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
{
int i, bit;
- IVTV_DEBUG_I2C("write %x\n",byte);
+ IVTV_DEBUG_HI_I2C("write %x\n",byte);
for (i = 0; i < 8; ++i, byte<<=1) {
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +318,7 @@ static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
ivtv_scldelay(itv);
ivtv_setscl(itv, 0);
ivtv_scldelay(itv);
- IVTV_DEBUG_I2C("read %x\n",*byte);
+ IVTV_DEBUG_HI_I2C("read %x\n",*byte);
return 0;
}
@@ -330,7 +330,7 @@ static int ivtv_start(struct ivtv *itv)
sda = ivtv_getsda(itv);
if (sda != 1) {
- IVTV_DEBUG_I2C("SDA was low at start\n");
+ IVTV_DEBUG_HI_I2C("SDA was low at start\n");
ivtv_setsda(itv, 1);
if (!ivtv_waitsda(itv, 1)) {
IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +355,7 @@ static int ivtv_stop(struct ivtv *itv)
int i;
if (ivtv_getscl(itv) != 0) {
- IVTV_DEBUG_I2C("SCL not low when stopping\n");
+ IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -569,7 +569,7 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
}
}
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+ IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
return -ENODEV;
}
@@ -640,7 +640,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
addr = ivtv_i2c_hw_addr(itv, hw);
if (addr < 0) {
- IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
hw, ivtv_i2c_hw_name(hw), cmd);
return addr;
}
@@ -655,7 +655,7 @@ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
addr = ivtv_i2c_id_addr(itv, id);
if (addr < 0) {
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
id, ivtv_i2c_id_name(id), cmd);
return addr;
}
@@ -696,7 +696,7 @@ int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
{
if (itv->i2c_adap.algo == NULL) {
- IVTV_ERR("adapter is not set");
+ IVTV_ERR("Adapter is not set");
return;
}
i2c_clients_command(&itv->i2c_adap, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 1a3ee464a82..fcd6e7f5f12 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -403,6 +403,11 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
/* Mark last buffer size for Interrupt flag */
s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+ if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+ set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+ else
+ clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+
if (ivtv_use_pio(s)) {
for (i = 0; i < s->SG_length; i++) {
s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
@@ -420,7 +425,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
}
@@ -437,7 +442,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
@@ -597,7 +602,6 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
data[0], data[1], data[2]);
return;
}
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
s = &itv->streams[ivtv_stream_map[data[0]]];
if (!stream_enc_dma_append(s, data)) {
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -634,7 +638,6 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
then start a DMA request for just the VBI data. */
if (!stream_enc_dma_append(s, data) &&
!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
- set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
}
}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 6ae42a3b03c..814a673712b 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -37,6 +37,7 @@
#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */
#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */
#define API_DMA (1 << 3) /* DMA mailbox, has special handling */
+#define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */
#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */
#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */
@@ -77,11 +78,11 @@ static const struct ivtv_api_info api_info[256] = {
API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT),
- API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA),
+ API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE),
API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT),
- API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB),
+ API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE),
API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE),
@@ -102,7 +103,7 @@ static const struct ivtv_api_info api_info[256] = {
API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT),
- API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA),
+ API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT),
API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE),
@@ -175,9 +176,9 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
/* Sleep before a retry, if not atomic */
if (!(flags & API_NO_WAIT_MB)) {
- if (jiffies - then > retries * HZ / 100)
+ if (jiffies - then > msecs_to_jiffies(10*retries))
break;
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
}
}
return -ENODEV;
@@ -212,7 +213,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
{
struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
volatile struct ivtv_mailbox __iomem *mbox;
- int api_timeout = HZ;
+ int api_timeout = msecs_to_jiffies(1000);
int flags, mb, i;
unsigned long then;
@@ -227,7 +228,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
return -EINVAL;
}
- IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ if (api_info[cmd].flags & API_HIGH_VOL) {
+ IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+ }
+ else {
+ IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ }
/* clear possibly uninitialized part of data array */
for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +243,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
data, then just return 0 as there is no need to issue this command again.
Just an optimization to prevent unnecessary use of mailboxes. */
if (itv->api_cache[cmd].last_jiffies &&
- jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+ jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
!memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
itv->api_cache[cmd].last_jiffies = jiffies;
return 0;
@@ -262,7 +268,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
- api_timeout = HZ / 10;
+ api_timeout = msecs_to_jiffies(100);
mb = get_mailbox(itv, mbdata, flags);
if (mb < 0) {
@@ -295,11 +301,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
if (flags & API_NO_WAIT_RES)
mdelay(1);
else
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
}
- if (jiffies - then > HZ / 10)
- IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
- api_info[cmd].name, jiffies - then, HZ);
+ if (jiffies - then > msecs_to_jiffies(100))
+ IVTV_DEBUG_WARN("%s took %u jiffies\n",
+ api_info[cmd].name,
+ jiffies_to_msecs(jiffies - then));
for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
data[i] = readl(&mbox->data[i]);
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 28711718749..322b347b67c 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -565,7 +565,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* Initialize Digitizer for Capture */
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
}
/* begin_capture */
@@ -781,8 +781,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
set_current_state(TASK_INTERRUPTIBLE);
/* wait 2s for EOS interrupt */
- while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
- schedule_timeout(HZ / 100);
+ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+ jiffies < then + msecs_to_jiffies (2000)) {
+ schedule_timeout(msecs_to_jiffies(10));
}
/* To convert jiffies to ms, we must multiply by 1000
@@ -821,7 +822,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
break;
}
- } while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies);
+ } while (!ivtv_msleep_timeout(10, 1) &&
+ then + msecs_to_jiffies(2000) > jiffies);
set_current_state(TASK_RUNNING);
remove_wait_queue(&s->waitq, &wait);
@@ -892,7 +894,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
break;
tmp = data[3];
}
- if (ivtv_sleep_timeout(HZ/10, 1))
+ if (ivtv_msleep_timeout(100, 1))
break;
}
}
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f2a2f34cd62..17f1e2e9a66 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -86,9 +86,9 @@ static const int disp_modes[8][3] =
-#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */
+#define PAGE_WAIT msecs_to_jiffies(300) /* Time between requesting page and */
/* checking status bits */
-#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000) /* Time to wait before retransmitting */
/* page regardless of infobits */
typedef struct {
u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
@@ -115,8 +115,8 @@ struct saa5249_device
#define CCTWR 34 /* I²C write/read-address of vtx-chip */
#define CCTRD 35
#define NOACK_REPEAT 10 /* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20) /* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000) /* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY msecs_to_jiffies(50) /* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30) /* Time to wait for ready signal of I2C-bus interface */
#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 676b9970eb2..061134a7ba9 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -208,7 +208,7 @@ determine_norm (struct i2c_client *client)
saa7110_write_block(client, initseq, sizeof(initseq));
saa7110_selmux(client, decoder->input);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
if (status & 0x40) {
@@ -249,7 +249,7 @@ determine_norm (struct i2c_client *client)
//saa7110_write(client,0x2E,0x9A);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index d32a856192d..346255468da 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -314,7 +314,7 @@ struct saa7134_board {
#define INTERLACE_ON 1
#define INTERLACE_OFF 2
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
struct saa7134_dev;
struct saa7134_dma;
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 9da338dc4f3..cffb011590e 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -290,7 +290,7 @@ static int chip_thread(void *data)
desc->checkmode(chip);
/* schedule next check */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
}
v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1770,7 @@ static int chip_command(struct i2c_client *client,
desc->setmode(chip,VIDEO_SOUND_MONO);
if (chip->prevmode != VIDEO_SOUND_MONO)
chip->prevmode = -1; /* reset previous mode */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
/* the thread will call checkmode() later */
}
break;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 13ee550d321..d2915d3530e 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -939,16 +939,25 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
When no more controls are available 0 is returned. */
u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
{
- u32 ctrl_class;
+ u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
const u32 *pctrl;
- /* if no query is desired, then just return the control ID */
- if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
- return id;
if (ctrl_classes == NULL)
return 0;
+
+ /* if no query is desired, then check if the ID is part of ctrl_classes */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+ /* find class */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find control ID */
+ while (*pctrl && *pctrl != id) pctrl++;
+ return *pctrl ? id : 0;
+ }
id &= V4L2_CTRL_ID_MASK;
- ctrl_class = V4L2_CTRL_ID2CLASS(id);
id++; /* select next control */
/* find first class that matches (or is greater than) the class of
the ID */
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index e94a9a6036f..a0c1647a2ba 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2080,7 +2080,7 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
/* to ensure that schedule_timeout will return immediately
* if VINO interrupt was triggered meanwhile */
- schedule_timeout_interruptible(HZ / 10);
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (signal_pending(current))
err = -EINTR;
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 8f6741a28a4..1bf4cbec6a8 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -321,12 +321,14 @@ static int wm8739_probe(struct i2c_adapter *adapter)
static int wm8739_detach(struct i2c_client *client)
{
+ struct wm8739_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err)
return err;
+ kfree(state);
kfree(client);
return 0;
}
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 4df5d30d4d0..9f7e894ef96 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -222,12 +222,14 @@ static int wm8775_probe(struct i2c_adapter *adapter)
static int wm8775_detach(struct i2c_client *client)
{
+ struct wm8775_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err) {
return err;
}
+ kfree(state);
kfree(client);
return 0;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 26a3b45a4a3..62c1c6262fe 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -608,7 +608,7 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
MODULE_LICENSE("GPL");
-int
+int __init
init_module(void)
{
net_debug = debug;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a2f32151559..13f08a390e1 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -692,6 +692,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 reg;
+ u32 rx_reg;
int i;
const u8 *addr = hw->dev[port]->dev_addr;
@@ -768,11 +769,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+ rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
if (hw->chip_id == CHIP_ID_YUKON_EX)
- reg |= GMF_RX_OVER_ON;
+ rx_reg |= GMF_RX_OVER_ON;
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
/* Flush Rx MAC FIFO on any flow control or error */
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index b801e3b3a11..61f98251fea 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
return 0;
}
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+ struct vio_net_mcast_info *pkt = msgbuf;
+
+ if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+ printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+ "[%02x:%02x:%04x:%08x]\n",
+ port->vp->dev->name,
+ pkt->tag.type,
+ pkt->tag.stype,
+ pkt->tag.stype_env,
+ pkt->tag.sid);
+
+ return 0;
+}
+
static void maybe_tx_wakeup(struct vnet *vp)
{
struct net_device *dev = vp->dev;
@@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event)
err = vnet_nack(port, &msgbuf);
}
} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
- err = vio_control_pkt_engine(vio, &msgbuf);
+ if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+ err = handle_mcast(port, &msgbuf);
+ else
+ err = vio_control_pkt_engine(vio, &msgbuf);
if (err)
break;
} else {
@@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev)
return 0;
}
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+ struct vnet_mcast_entry *m;
+
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (!memcmp(m->addr, addr, ETH_ALEN))
+ return m;
+ }
+ return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+ struct dev_addr_list *p;
+
+ for (p = dev->mc_list; p; p = p->next) {
+ struct vnet_mcast_entry *m;
+
+ m = __vnet_mc_find(vp, p->dmi_addr);
+ if (m) {
+ m->hit = 1;
+ continue;
+ }
+
+ if (!m) {
+ m = kzalloc(sizeof(*m), GFP_ATOMIC);
+ if (!m)
+ continue;
+ memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+ m->hit = 1;
+
+ m->next = vp->mcast_list;
+ vp->mcast_list = m;
+ }
+ }
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+ struct vio_net_mcast_info info;
+ struct vnet_mcast_entry *m, **pp;
+ int n_addrs;
+
+ memset(&info, 0, sizeof(info));
+
+ info.tag.type = VIO_TYPE_CTRL;
+ info.tag.stype = VIO_SUBTYPE_INFO;
+ info.tag.stype_env = VNET_MCAST_INFO;
+ info.tag.sid = vio_send_sid(&port->vio);
+ info.set = 1;
+
+ n_addrs = 0;
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (m->sent)
+ continue;
+ m->sent = 1;
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+
+ info.set = 0;
+
+ n_addrs = 0;
+ pp = &vp->mcast_list;
+ while ((m = *pp) != NULL) {
+ if (m->hit) {
+ m->hit = 0;
+ pp = &m->next;
+ continue;
+ }
+
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+
+ *pp = m->next;
+ kfree(m);
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+}
+
static void vnet_set_rx_mode(struct net_device *dev)
{
- /* XXX Implement multicast support XXX */
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ if (!list_empty(&vp->port_list)) {
+ port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+ if (port->switch_port) {
+ __update_mc_list(vp, dev);
+ __send_mc_list(vp, port);
+ }
+ }
+ spin_unlock_irqrestore(&vp->lock, flags);
}
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
switch_port = 0;
if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
switch_port = 1;
+ port->switch_port = switch_port;
spin_lock_irqsave(&vp->lock, flags);
if (switch_port)
@@ -1136,7 +1269,7 @@ static struct vio_device_id vnet_port_match[] = {
},
{},
};
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
static struct vio_driver vnet_port_driver = {
.id_table = vnet_port_match,
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 7d3a0cac727..d347a5bf24b 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -30,6 +30,8 @@ struct vnet_port {
struct hlist_node hash;
u8 raddr[ETH_ALEN];
+ u8 switch_port;
+ u8 __pad;
struct vnet *vp;
@@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
return val & (VNET_PORT_HASH_MASK);
}
+struct vnet_mcast_entry {
+ u8 addr[ETH_ALEN];
+ u8 sent;
+ u8 hit;
+ struct vnet_mcast_entry *next;
+};
+
struct vnet {
/* Protects port_list and port_hash. */
spinlock_t lock;
@@ -65,6 +74,8 @@ struct vnet {
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
+ struct vnet_mcast_entry *mcast_list;
+
struct list_head list;
u64 local_mac;
};
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 00000000000..c03072b12f4
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,3 @@
+config OF_DEVICE
+ def_bool y
+ depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 00000000000..ab9be5d5255
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 00000000000..9377f3bc410
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ * 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; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ read_lock(&devtree_lock);
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (of_prop_cmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ read_unlock(&devtree_lock);
+
+ return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char* cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ * of_get_parent - Get a node's parent if any
+ * @node: Node to get parent
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ read_lock(&devtree_lock);
+ np = of_node_get(node->parent);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ * of_get_next_child - Iterate a node childs
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ read_lock(&devtree_lock);
+ next = prev ? prev->sibling : node->child;
+ for (; next; next = next->sibling)
+ if (of_node_get(next))
+ break;
+ of_node_put(prev);
+ read_unlock(&devtree_lock);
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np = allnodes;
+
+ read_lock(&devtree_lock);
+ for (; np; np = np->allnext) {
+ if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+ && of_node_get(np))
+ break;
+ }
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ * of_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @name: The name string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->name && (of_node_cmp(np->name, name) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
+ * the entire device tree. The node you pass will not be
+ * searched, only the next one will; typically, you pass
+ * what the previous call returned. of_node_put() will be
+ * called on from for you.
+ * @type: The type string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->type && (of_node_cmp(np->type, type) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ * of_find_compatible_node - Find a node based on type and one of the
+ * tokens in its "compatible" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @type: The type string to match "device_type" or NULL to ignore
+ * @compatible: The string to match to one of the tokens in the device
+ * "compatible" list.
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ if (type
+ && !(np->type && (of_node_cmp(np->type, type) == 0)))
+ continue;
+ if (of_device_is_compatible(np, compatible) && of_node_get(np))
+ break;
+ }
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644
index 00000000000..6245f060fb7
--- /dev/null
+++ b/drivers/of/device.c
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= node->name
+ && !strcmp(matches->name, node->name);
+ if (matches->type[0])
+ match &= node->type
+ && !strcmp(matches->type, node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ of_node_put(ofdev->node);
+ kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+ if (rc)
+ device_unregister(&ofdev->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644
index 00000000000..864f09fd9f8
--- /dev/null
+++ b/drivers/of/platform.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ * and Arnd Bergmann, IBM Corp.
+ * Merged from powerpc/kernel/of_platform.c and
+ * sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ * 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; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+ const struct of_device_id *matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+ bus->name = name;
+ bus->match = of_platform_bus_match;
+ bus->probe = of_platform_device_probe;
+ bus->remove = of_platform_device_remove;
+ bus->suspend = of_platform_device_suspend;
+ bus->resume = of_platform_device_resume;
+ return bus_register(bus);
+}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index edd6de99572..8134c7e198a 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
#include <linux/profile.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/oprofile.h>
#include <linux/sched.h>
-
+
#include "oprofile_stats.h"
#include "event_buffer.h"
#include "cpu_buffer.h"
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 9b6a4ebd03e..5076ed1ebd8 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@ void free_event_buffer(void);
/* wake up the process sleeping on the event file */
void wake_up_buffer_waiter(void);
-
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE ~0UL
-#define CTX_SWITCH_CODE 1
-#define CPU_SWITCH_CODE 2
-#define COOKIE_SWITCH_CODE 3
-#define KERNEL_ENTER_SWITCH_CODE 4
-#define KERNEL_EXIT_SWITCH_CODE 5
-#define MODULE_LOADED_CODE 6
-#define CTX_TGID_CODE 7
-#define TRACE_BEGIN_CODE 8
-#define TRACE_END_CODE 9
-
+
#define INVALID_COOKIE ~0UL
#define NO_COOKIE 0UL
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
-
extern const struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index e5162a64018..2c645170f06 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@ int oprofile_setup(void)
* us missing task deaths and eventually oopsing
* when trying to process the event buffer.
*/
+ if (oprofile_ops.sync_start) {
+ int sync_ret = oprofile_ops.sync_start();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ case -1:
+ goto out3;
+ default:
+ goto out3;
+ }
+ }
+do_generic:
if ((err = sync_start()))
goto out3;
+post_sync:
is_setup = 1;
mutex_unlock(&start_mutex);
return 0;
@@ -118,7 +133,20 @@ out:
void oprofile_shutdown(void)
{
mutex_lock(&start_mutex);
+ if (oprofile_ops.sync_stop) {
+ int sync_ret = oprofile_ops.sync_stop();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ default:
+ goto post_sync;
+ }
+ }
+do_generic:
sync_stop();
+post_sync:
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 09c93ff932b..d449b150930 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -35,7 +35,7 @@ if PARPORT
config PARPORT_PC
tristate "PC-style hardware"
- depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+ depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
---help---
You should say Y here if you have a PC-style parallel port. All
IBM PC compatible computers and some Alphas have PC-style
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cea401feb0f..35f34665e3c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -394,7 +394,7 @@ config RTC_DRV_SA1100
config RTC_DRV_SH
tristate "SuperH On-Chip RTC"
- depends on RTC_CLASS && SUPERH
+ depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4)
help
Say Y here to enable support for the on-chip RTC found in
most SuperH processors.
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 002643392d4..2553629ec15 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
+ struct dev_archdata *sd;
unsigned long base;
const void *pval;
int len, err;
@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
sbus_fill_device_irq(sdev);
+ sd = &sdev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &sdev->ofdev;
+
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 372723161c9..a947257b896 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -483,7 +483,7 @@ source "drivers/scsi/aic94xx/Kconfig"
# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
tristate "Adaptec I2O RAID support "
- depends on !64BIT && SCSI && PCI
+ depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
help
This driver supports all of Adaptec's I2O based RAID controllers as
well as the DPT SmartRaid V cards. This is an Adaptec maintained
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 773d11dd995..79b4df15814 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -95,6 +95,8 @@ enum {
/* The master ring of all esp hosts we are managing in this driver. */
static struct NCR_ESP *espchain;
int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
irqreturn_t esp_intr(int irq, void *dev_id);
@@ -524,6 +526,7 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Eat any bitrot in the chip and we are done... */
trash = esp_read(eregs->esp_intrpt);
}
+EXPORT_SYMBOL(esp_bootup_reset);
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
@@ -772,6 +775,7 @@ const char *esp_info(struct Scsi_Host *host)
panic("Bogon ESP revision");
};
}
+EXPORT_SYMBOL(esp_info);
/* From Wolfgang Stanglmeier's NCR scsi driver. */
struct info_str
@@ -902,6 +906,7 @@ int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t off
*start = buffer;
return esp_host_info(esp, buffer, offset, length);
}
+EXPORT_SYMBOL(esp_proc_info);
static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
@@ -3535,6 +3540,7 @@ state_machine:
if(esp->dma_irq_exit)
esp->dma_irq_exit(esp);
}
+EXPORT_SYMBOL(esp_handle);
#ifndef CONFIG_SMP
irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3631,6 +3637,7 @@ void esp_release(void)
esps_in_use--;
esps_running = esps_in_use;
}
+EXPORT_SYMBOL(esp_release);
#endif
EXPORT_SYMBOL(esp_abort);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index aebcd5fcdc5..7829ab1e2fb 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1885,7 +1885,7 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
struct sockaddr_in *sin;
int rc = 0, len;
- addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
if (!addr)
return -ENOMEM;
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba5392dd..70a09a3d5af 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/serial_core.h>
#include <linux/init.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
#include "suncore.h"
@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor);
-void
-sunserial_console_termios(struct console *con)
+int sunserial_console_match(struct console *con, struct device_node *dp,
+ struct uart_driver *drv, int line)
{
- char mode[16], buf[16], *s;
- char mode_prop[] = "ttyX-mode";
- char cd_prop[] = "ttyX-ignore-cd";
- char dtr_prop[] = "ttyX-rts-dtr-off";
- char *ssp_console_modes_prop = "ssp-console-modes";
- int baud, bits, stop, cflag;
- char parity;
- int carrier = 0;
- int rtsdtr = 1;
- int topnd, nd;
-
- if (!serial_console)
- return;
-
- switch (serial_console) {
- case PROMDEV_OTTYA:
- mode_prop[3] = 'a';
- cd_prop[3] = 'a';
- dtr_prop[3] = 'a';
- break;
-
- case PROMDEV_OTTYB:
- mode_prop[3] = 'b';
- cd_prop[3] = 'b';
- dtr_prop[3] = 'b';
- break;
-
- case PROMDEV_ORSC:
-
- nd = prom_pathtoinode("rsc");
- if (!nd) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ int off;
- if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ if (!con || of_console_device != dp)
+ return 0;
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
- goto no_options;
+ off = 0;
+ if (of_console_options &&
+ *of_console_options == 'b')
+ off = 1;
- default:
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ if ((line & 1) != off)
+ return 0;
- topnd = prom_getchild(prom_root_node);
- nd = prom_searchsiblings(topnd, "options");
- if (!nd) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
-
- if (!prom_node_has_property(nd, mode_prop)) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ con->index = line;
+ drv->cons = con;
+ add_preferred_console(con->name, line, NULL);
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
- if (prom_node_has_property(nd, cd_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, cd_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- carrier = 1;
-
- /* XXX: this is unused below. */
- }
+ return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
- if (prom_node_has_property(nd, dtr_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, dtr_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- rtsdtr = 0;
+void
+sunserial_console_termios(struct console *con)
+{
+ struct device_node *dp;
+ const char *od, *mode, *s;
+ char mode_prop[] = "ttyX-mode";
+ int baud, bits, stop, cflag;
+ char parity;
- /* XXX: this is unused below. */
+ dp = of_find_node_by_path("/options");
+ od = of_get_property(dp, "output-device", NULL);
+ if (!strcmp(od, "rsc")) {
+ mode = of_get_property(of_console_device,
+ "ssp-console-modes", NULL);
+ if (!mode)
+ mode = "115200,8,n,1,-";
+ } else {
+ char c;
+
+ c = 'a';
+ if (of_console_options)
+ c = *of_console_options;
+
+ mode_prop[3] = c;
+
+ mode = of_get_property(dp, mode_prop, NULL);
+ if (!mode)
+ mode = "9600,8,n,1,-";
}
-no_options:
cflag = CREAD | HUPCL | CLOCAL;
s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a8ce3..829d7d65d6d 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor;
+extern int sunserial_console_match(struct console *, struct device_node *,
+ struct uart_driver *, int);
extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index d82be42ff29..8ff900b0981 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -520,16 +520,6 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
-static inline struct console *SUNHV_CONSOLE(void)
-{
- if (con_is_present())
- return NULL;
-
- sunhv_console.index = 0;
-
- return &sunhv_console;
-}
-
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
- sunhv_reg.cons = SUNHV_CONSOLE();
+ sunserial_console_match(&sunhv_console, op->node,
+ &sunhv_reg, port->line);
err = uart_add_one_port(&sunhv_reg, port);
if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8a0f9e4408d..bca57bb9493 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -968,22 +968,6 @@ static struct console sunsab_console = {
static inline struct console *SUNSAB_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_channels; i++) {
- int this_minor = sunsab_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_channels)
- return NULL;
-
- sunsab_console.index = i;
-
return &sunsab_console;
}
#else
@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
return err;
}
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[0].port.line);
uart_add_one_port(&sunsab_reg, &up[0].port);
+
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[1].port.line);
uart_add_one_port(&sunsab_reg, &up[1].port);
dev_set_drvdata(&op->dev, &up[0]);
@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void)
}
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
- sunsab_reg.cons = SUNSAB_CONSOLE();
sunserial_current_minor += num_channels;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 26d720baf88..79b13685bdf 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1371,28 +1371,12 @@ static struct console sunsu_console = {
* Register console.
*/
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_uart; i++) {
- int this_minor = sunsu_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_uart)
- return NULL;
-
- sunsu_console.index = i;
-
return &sunsu_console;
}
#else
-#define SUNSU_CONSOLE(num_uart) (NULL)
+#define SUNSU_CONSOLE() (NULL)
#define sunsu_serial_console_init() do { } while (0)
#endif
@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
up->port.ops = &sunsu_pops;
+ sunserial_console_match(SUNSU_CONSOLE(), dp,
+ &sunsu_reg, up->port.line);
err = uart_add_one_port(&sunsu_reg, &up->port);
if (err)
goto out_unmap;
@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void)
return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart;
- sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
}
err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 0a3e10a4a35..1d262c0c613 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
static inline struct console *SUNZILOG_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- int this_minor = sunzilog_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == NUM_CHANNELS)
- return NULL;
-
- sunzilog_console_ops.index = i;
- sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
return &sunzilog_console_ops;
}
@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
sunzilog_init_hw(&up[1]);
if (!keyboard_mouse) {
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[0].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
of_iounmap(&op->resource[0],
rp, sizeof(struct zilog_layout));
return err;
}
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[1].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void)
goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
- sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count;
}
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 1bc884051e0..02c52f8d5db 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -456,7 +456,7 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length)
{
struct timer_list timer;
- int status;
+ int status = urb->status;
init_timer(&timer);
timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,7 +464,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
timer.function = cxacru_timeout_kill;
add_timer(&timer);
wait_for_completion(done);
- status = urb->status;
del_timer_sync(&timer);
if (actual_length)
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 638b8009b3b..eb0615abff6 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -612,7 +612,8 @@ static void speedtch_handle_int(struct urb *int_urb)
struct speedtch_instance_data *instance = int_urb->context;
struct usbatm_data *usbatm = instance->usbatm;
unsigned int count = int_urb->actual_length;
- int ret = int_urb->status;
+ int status = int_urb->status;
+ int ret;
/* The magic interrupt for "up state" */
static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +622,8 @@ static void speedtch_handle_int(struct urb *int_urb)
atm_dbg(usbatm, "%s entered\n", __func__);
- if (ret < 0) {
- atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+ if (status < 0) {
+ atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
goto fail;
}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 8f046659b4e..a1a1c9d467e 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1308,11 +1308,13 @@ static void uea_intr(struct urb *urb)
{
struct uea_softc *sc = urb->context;
struct intr_pkt *intr = urb->transfer_buffer;
+ int status = urb->status;
+
uea_enters(INS_TO_USBDEV(sc));
- if (unlikely(urb->status < 0)) {
+ if (unlikely(status < 0)) {
uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
- urb->status);
+ status);
return;
}
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 11e9b15ca45..e717f5b1cae 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb)
{
struct usbatm_channel *channel = urb->context;
unsigned long flags;
+ int status = urb->status;
vdbg("%s: urb 0x%p, status %d, actual_length %d",
- __func__, urb, urb->status, urb->actual_length);
+ __func__, urb, status, urb->actual_length);
/* usually in_interrupt(), but not always */
spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb)
spin_unlock_irqrestore(&channel->lock, flags);
- if (unlikely(urb->status) &&
+ if (unlikely(status) &&
(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
- urb->status != -EILSEQ ))
+ status != -EILSEQ ))
{
- if (urb->status == -ESHUTDOWN)
+ if (status == -ESHUTDOWN)
return;
if (printk_ratelimit())
atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
- __func__, urb, urb->status);
+ __func__, urb, status);
/* throttle processing in case of an error */
mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
} else
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index cd51520c7e7..fe940e0536e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb)
struct usb_cdc_notification *dr = urb->transfer_buffer;
unsigned char *data;
int newctrl;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
@@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb)
break;
}
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
/* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb)
struct acm_ru *rcv = urb->context;
struct acm *acm = rcv->instance;
int status = urb->status;
- dbg("Entering acm_read_bulk with status %d", urb->status);
+
+ dbg("Entering acm_read_bulk with status %d", status);
if (!ACM_READY(acm))
return;
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 9a1478972bf..5192cd9356d 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -289,16 +289,17 @@ static int proto_bias = -1;
static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
if (usblp->present && usblp->used) {
- if (urb->status)
+ if (status)
printk(KERN_WARNING "usblp%d: "
"nonzero read bulk status received: %d\n",
- usblp->minor, urb->status);
+ usblp->minor, status);
}
spin_lock(&usblp->lock);
- if (urb->status < 0)
- usblp->rstatus = urb->status;
+ if (status < 0)
+ usblp->rstatus = status;
else
usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1;
@@ -311,16 +312,17 @@ static void usblp_bulk_read(struct urb *urb)
static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
if (usblp->present && usblp->used) {
- if (urb->status)
+ if (status)
printk(KERN_WARNING "usblp%d: "
"nonzero write bulk status received: %d\n",
- usblp->minor, urb->status);
+ usblp->minor, status);
}
spin_lock(&usblp->lock);
- if (urb->status < 0)
- usblp->wstatus = urb->status;
+ if (status < 0)
+ usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
usblp->wcomplete = 1;
@@ -741,10 +743,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
*/
rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
if (rv < 0) {
- /*
- * If interrupted, we simply leave the URB to dangle,
- * so the ->release will call usb_kill_urb().
- */
+ if (rv == -EAGAIN) {
+ /* Presume that it's going to complete well. */
+ writecount += transfer_length;
+ }
+ /* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 963520fbef9..42ef1d5f6c8 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock);
/* used for controlling access to virtual root hubs */
static DEFINE_SPINLOCK(hcd_root_hub_lock);
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
/* wait queue for synchronous unlinks */
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
+static inline int is_root_hub(struct usb_device *udev)
+{
+ return (udev->parent == NULL);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -906,14 +911,13 @@ EXPORT_SYMBOL (usb_calc_bus_time);
static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
- int at_root_hub = (urb->dev == hcd->self.root_hub);
/* clear all state linking urb to this dev (and hcd) */
- spin_lock_irqsave (&hcd_data_lock, flags);
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
list_del_init (&urb->urb_list);
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
- if (hcd->self.uses_dma && !at_root_hub) {
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -955,7 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
// FIXME: verify that quiescing hc works right (RH cleans up)
- spin_lock_irqsave (&hcd_data_lock, flags);
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (unlikely (!ep))
@@ -972,7 +976,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
status = -ESHUTDOWN;
break;
}
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
usbmon_urb_submit_error(&hcd->self, urb, status);
@@ -986,7 +990,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
urb = usb_get_urb (urb);
atomic_inc (&urb->use_count);
- if (urb->dev == hcd->self.root_hub) {
+ if (is_root_hub(urb->dev)) {
/* NOTE: requirement on hub callers (usbfs and the hub
* driver, for now) that URBs' urb->transfer_buffer be
* valid and usb_buffer_{sync,unmap}() not be needed, since
@@ -1033,18 +1037,6 @@ done:
/*-------------------------------------------------------------------------*/
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
-{
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-
- if (!HC_IS_RUNNING (hcd->state))
- return -ESHUTDOWN;
- return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
/* this makes the hcd giveback() the urb more quickly, by kicking it
* off hardware queues (which may take a while) and returning it as
* soon as practical. we've already set up the urb's return status,
@@ -1055,7 +1047,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
{
int value;
- if (urb->dev == hcd->self.root_hub)
+ if (is_root_hub(urb->dev))
value = usb_rh_urb_dequeue (hcd, urb);
else {
@@ -1103,11 +1095,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* that it was submitted. But as a rule it can't know whether or
* not it's already been unlinked ... so we respect the reversed
* lock sequence needed for the usb_hcd_giveback_urb() code paths
- * (urb lock, then hcd_data_lock) in case some other CPU is now
+ * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
* unlinking it.
*/
spin_lock_irqsave (&urb->lock, flags);
- spin_lock (&hcd_data_lock);
+ spin_lock(&hcd_urb_list_lock);
sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
@@ -1139,17 +1131,16 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
- && hcd->self.root_hub != urb->dev) {
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ."
- "\n");
+ "Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
urb->status = status;
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
retval = unlink1 (hcd, urb);
@@ -1158,7 +1149,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
return retval;
done:
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
if (retval != -EIDRM && sys && sys->driver)
dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1167,6 +1158,35 @@ done:
/*-------------------------------------------------------------------------*/
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function. The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv). It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+ urb_unlink(hcd, urb);
+ usbmon_urb_complete (&hcd->self, urb);
+ usb_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->complete (urb);
+ atomic_dec (&urb->use_count);
+ if (unlikely (urb->reject))
+ wake_up (&usb_kill_urb_queue);
+ usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
/* disables the endpoint: cancels any pending urbs, then synchronizes with
* the hcd to make sure all endpoint state is gone from hardware, and then
* waits until the endpoint's queue is completely drained. use for
@@ -1186,7 +1206,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
- spin_lock (&hcd_data_lock);
+ spin_lock(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
@@ -1194,7 +1214,7 @@ rescan:
if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_lock (&urb->lock);
tmp = urb->status;
@@ -1223,7 +1243,7 @@ rescan:
/* list contents may have changed */
goto rescan;
}
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
local_irq_enable ();
/* synchronize with the hardware, so old configuration state
@@ -1240,7 +1260,7 @@ rescan:
* endpoint_disable methods.
*/
while (!list_empty (&ep->urb_list)) {
- spin_lock_irq (&hcd_data_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
/* The list may have changed while we acquired the spinlock */
urb = NULL;
@@ -1249,7 +1269,7 @@ rescan:
urb_list);
usb_get_urb (urb);
}
- spin_unlock_irq (&hcd_data_lock);
+ spin_unlock_irq(&hcd_urb_list_lock);
if (urb) {
usb_kill_urb (urb);
@@ -1260,6 +1280,18 @@ rescan:
/*-------------------------------------------------------------------------*/
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HC_IS_RUNNING (hcd->state))
+ return -ESHUTDOWN;
+ return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
#ifdef CONFIG_PM
int hcd_bus_suspend(struct usb_device *rhdev)
@@ -1395,35 +1427,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function. The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv). It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
- urb_unlink(hcd, urb);
- usbmon_urb_complete (&hcd->self, urb);
- usb_unanchor_urb(urb);
-
- /* pass ownership to the completion handler */
- urb->complete (urb);
- atomic_dec (&urb->use_count);
- if (unlikely (urb->reject))
- wake_up (&usb_kill_urb_queue);
- usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
-/**
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
* @__hcd: pointer to the HCD whose IRQ is being signaled
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index fd74c50b180..e341a1da517 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1335,6 +1335,10 @@ int usb_new_device(struct usb_device *udev)
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+ /* Increment the parent's count of unsuspended children */
+ if (udev->parent)
+ usb_autoresume_device(udev->parent);
+
/* Register the device. The device driver is responsible
* for adding the device files to sysfs and for configuring
* the device.
@@ -1342,13 +1346,11 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ if (udev->parent)
+ usb_autosuspend_device(udev->parent);
goto fail;
}
- /* Increment the parent's count of unsuspended children */
- if (udev->parent)
- usb_autoresume_device(udev->parent);
-
exit:
return err;
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 530e854961c..25f63f1096b 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -34,13 +34,14 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct completion done;
unsigned long expire;
- int status;
+ int retval;
+ int status = urb->status;
init_completion(&done);
urb->context = &done;
urb->actual_length = 0;
- status = usb_submit_urb(urb, GFP_NOIO);
- if (unlikely(status))
+ retval = usb_submit_urb(urb, GFP_NOIO);
+ if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
@@ -55,15 +56,15 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
urb->transfer_buffer_length);
usb_kill_urb(urb);
- status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+ retval = status == -ENOENT ? -ETIMEDOUT : status;
} else
- status = urb->status;
+ retval = status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
- return status;
+ return retval;
}
/*-------------------------------------------------------------------*/
@@ -250,6 +251,7 @@ static void sg_clean (struct usb_sg_request *io)
static void sg_complete (struct urb *urb)
{
struct usb_sg_request *io = urb->context;
+ int status = urb->status;
spin_lock (&io->lock);
@@ -265,21 +267,21 @@ static void sg_complete (struct urb *urb)
*/
if (io->status
&& (io->status != -ECONNRESET
- || urb->status != -ECONNRESET)
+ || status != -ECONNRESET)
&& urb->actual_length) {
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- urb->status, io->status);
+ status, io->status);
// BUG ();
}
- if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
- int i, found, status;
+ if (io->status == 0 && status && status != -ECONNRESET) {
+ int i, found, retval;
- io->status = urb->status;
+ io->status = status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +292,13 @@ static void sg_complete (struct urb *urb)
if (!io->urbs [i] || !io->urbs [i]->dev)
continue;
if (found) {
- status = usb_unlink_urb (io->urbs [i]);
- if (status != -EINPROGRESS
- && status != -ENODEV
- && status != -EBUSY)
+ retval = usb_unlink_urb (io->urbs [i]);
+ if (retval != -EINPROGRESS &&
+ retval != -ENODEV &&
+ retval != -EBUSY)
dev_err (&io->dev->dev,
"%s, unlink --> %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} else if (urb == io->urbs [i])
found = 1;
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d47ae89154a..2ab222be8fd 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -441,6 +441,54 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct usb_device *udev = to_usb_device(
+ container_of(kobj, struct device, kobj));
+ size_t nleft = count;
+ size_t srclen, n;
+
+ usb_lock_device(udev);
+
+ /* The binary attribute begins with the device descriptor */
+ srclen = sizeof(struct usb_device_descriptor);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + (char *) &udev->descriptor, n);
+ nleft -= n;
+ buf += n;
+ off = 0;
+ } else {
+ off -= srclen;
+ }
+
+ /* Then follows the raw descriptor entry for the current
+ * configuration (config plus subsidiary descriptors).
+ */
+ if (udev->actconfig) {
+ int cfgno = udev->actconfig - udev->config;
+
+ srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+ nleft -= n;
+ }
+ }
+ usb_unlock_device(udev);
+ return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+ .attr = {.name = "descriptors", .mode = 0444},
+ .read = read_descriptors,
+ .size = 18 + 65535, /* dev descr + max-size raw descriptor */
+};
+
int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@@ -450,6 +498,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
+ retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+ if (retval)
+ goto error;
+
retval = add_persist_attributes(dev);
if (retval)
goto error;
@@ -492,6 +544,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
device_remove_file(dev, &dev_attr_serial);
remove_power_attributes(dev);
remove_persist_attributes(dev);
+ device_remove_bin_file(dev, &dev_bin_attr_descriptors);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 52ec44b828f..be630228461 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -440,55 +440,57 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* @urb: pointer to urb describing a previously submitted request,
* may be NULL
*
- * This routine cancels an in-progress request. URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
- *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver. When it is called, the completion
- * function will see urb->status == -ECONNRESET. Failure is indicated
- * by any other return value. Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This routine cancels an in-progress request. URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * This request is always asynchronous. Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver. When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
*
* Unlinking and Endpoint Queues:
*
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
* Host Controller Drivers (HCDs) place all the URBs for a particular
* endpoint in a queue. Normally the queue advances as the controller
* hardware processes each request. But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns. It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns. Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
- *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
- *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
- *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates. Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets. It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns. It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns. The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO. Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors. Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates. Such queues do not stop when an URB
+ * encounters an error or is unlinked. An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
*/
int usb_unlink_urb(struct urb *urb)
{
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 45e01e28945..767aed5b4be 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -82,6 +82,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536 UDC"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+ It is a USB Highspeed DMA capable USB device controller. Beside ep0
+ it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ The UDC port supports OTG operation, and may be used as a host port
+ if it's not being used to implement peripheral or OTG roles.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+ tristate
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -156,6 +177,24 @@ config USB_PXA2XX_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
+config USB_GADGET_M66592
+ boolean "Renesas M66592 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
+ help
+ M66592 is a discrete USB peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has seven configurable endpoints, and endpoint zero.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "m66592_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_M66592
+ tristate
+ depends on USB_GADGET_M66592
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
@@ -261,24 +300,6 @@ config USB_AT91
depends on USB_GADGET_AT91
default USB_GADGET
-config USB_GADGET_M66592
- boolean "M66592 driver"
- select USB_GADGET_DUALSPEED
- help
- M66592 is a USB 2.0 peripheral controller.
-
- It has seven configurable endpoints, and endpoint zero.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "m66592_udc" and force all
- gadget drivers to also be dynamically linked.
-
-config USB_M66592
- tristate
- depends on USB_GADGET_M66592
- default USB_GADGET
- select USB_GADGET_SELECTED
-
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 8ae76f73863..1bc0f03550c 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -7,6 +7,7 @@ endif
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 00000000000..714156ca8fe
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde 0 == do not touch RDE, do no start the RDE timer
+ * set_rde 1 == timer function will look whether FIFO has data
+ * set_rde 2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+ (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+ ep0_string,
+ "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+ "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+ "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+ "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+ "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+ "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+ "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+ "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+ DBG(dev, "------- Device registers -------\n");
+ DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg));
+ DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl));
+ DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts));
+ DBG(dev, "\n");
+ DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts));
+ DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts));
+ DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "USE DMA = %d\n", use_dma);
+ if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBNDU (packet per buffer "
+ "WITHOUT desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+ } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBDU (packet per buffer "
+ "WITH desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+ }
+ if (use_dma && use_dma_bufferfill_mode) {
+ DBG(dev, "DMA mode = BF (buffer fill mode)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+ }
+ if (!use_dma) {
+ dev_info(&dev->pdev->dev, "FIFO mode\n");
+ }
+ DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ /* mask all dev interrupts */
+ tmp = AMD_BIT(UDC_DEVINT_SVC) |
+ AMD_BIT(UDC_DEVINT_ENUM) |
+ AMD_BIT(UDC_DEVINT_US) |
+ AMD_BIT(UDC_DEVINT_UR) |
+ AMD_BIT(UDC_DEVINT_ES) |
+ AMD_BIT(UDC_DEVINT_SI) |
+ AMD_BIT(UDC_DEVINT_SOF)|
+ AMD_BIT(UDC_DEVINT_SC);
+ writel(tmp, &dev->regs->irqmsk);
+
+ /* mask all ep interrupts */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ /* enable ep0 irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+ & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "enable device interrupts for setup data\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->irqmsk);
+
+ /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+ writel(tmp, &dev->regs->irqmsk);
+
+ return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+ struct udc *dev;
+ u32 tmp;
+ int i;
+
+ if (!ep || !(ep->in))
+ return -EINVAL;
+
+ dev = ep->dev;
+ ep->txfifo = dev->txfifo;
+
+ /* traverse ep's */
+ for (i = 0; i < ep->num; i++) {
+ if (dev->ep[i].regs) {
+ /* read fifo size */
+ tmp = readl(&dev->ep[i].regs->bufin_framenum);
+ tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+ ep->txfifo += tmp;
+ }
+ }
+ return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+ if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+ DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+ cnak_pending |= 1 << (num);
+ ep->naking = 1;
+ } else
+ cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+ struct udc_ep *ep;
+ struct udc *dev;
+ u32 tmp;
+ unsigned long iflags;
+ u8 udc_csr_epix;
+
+ if (!usbep
+ || usbep->name == ep0_string
+ || !desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ dev = ep->dev;
+
+ DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ ep->desc = desc;
+
+ ep->halted = 0;
+
+ /* set traffic type */
+ tmp = readl(&dev->ep[ep->num].regs->ctl);
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+ writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+ /* set max packet size */
+ tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = desc->wMaxPacketSize;
+ writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+ /* IN ep */
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+ /* set buffer size (tx fifo entries) */
+ tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+ /* double buffering: fifo size = 2 x max packet size */
+ tmp = AMD_ADDBITS(
+ tmp,
+ desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+ / UDC_DWORD_BYTES,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+ /* calc. tx fifo base addr */
+ udc_set_txfifo_addr(ep);
+
+ /* flush fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+ /* set max packet size UDC CSR */
+ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+ if (use_dma && !ep->in) {
+ /* alloc and init BNA dummy request */
+ ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+ ep->bna_occurred = 0;
+ }
+
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_enabled = 1;
+ }
+
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* max packet */
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ /* ep number */
+ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+ /* ep direction */
+ tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+ /* ep type */
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+ /* ep config */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ /*
+ * clear NAK by writing CNAK
+ * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+ */
+ if (!use_dma || ep->in) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ tmp = desc->bEndpointAddress;
+ DBG(dev, "%s enabled\n", usbep->name);
+
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+ u32 tmp;
+
+ VDBG(ep->dev, "ep-%d reset\n", ep->num);
+ ep->desc = NULL;
+ ep->ep.ops = &udc_ep_ops;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->ep.maxpacket = (u16) ~0;
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+
+ /* disable interrupt */
+ tmp = readl(&regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, &regs->ep_irqmsk);
+
+ if (ep->in) {
+ /* unset P and IN bit of potential former DMA */
+ tmp = readl(&ep->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+
+ tmp = readl(&ep->regs->sts);
+ tmp |= AMD_BIT(UDC_EPSTS_IN);
+ writel(tmp, &ep->regs->sts);
+
+ /* flush the fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ }
+ /* reset desc pointer */
+ writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+ struct udc_ep *ep = NULL;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (usbep->name == ep0_string || !ep->desc)
+ return -EINVAL;
+
+ DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+ empty_req_queue(ep);
+ ep_init(ep->dev->regs, ep);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+ return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+ struct udc_request *req;
+ struct udc_data_dma *dma_desc;
+ struct udc_ep *ep;
+
+ if (!usbep)
+ return NULL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+
+ VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+ req = kzalloc(sizeof(struct udc_request), gfp);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_DONT_USE;
+ INIT_LIST_HEAD(&req->queue);
+
+ if (ep->dma) {
+ /* ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+ &req->td_phys);
+ if (!dma_desc) {
+ kfree(req);
+ return NULL;
+ }
+
+ VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+ "td_phys = %lx\n",
+ req, dma_desc,
+ (unsigned long)req->td_phys);
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status = AMD_ADDBITS(dma_desc->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+ req->td_data = dma_desc;
+ req->td_data_last = NULL;
+ req->chain_len = 1;
+ }
+
+ return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+
+ if (!usbep || !usbreq)
+ return;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ req = container_of(usbreq, struct udc_request, req);
+ VDBG(ep->dev, "free_req req=%p\n", req);
+ BUG_ON(!list_empty(&req->queue));
+ if (req->td_data) {
+ VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+ /* free dma chain if created */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+
+ pci_pool_free(ep->dev->data_requests, req->td_data,
+ req->td_phys);
+ }
+ kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+ if (req) {
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* set next pointer to itself */
+ req->td_data->next = req->td_phys;
+ /* set HOST BUSY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_DMA_DONE,
+ UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+ pr_debug("bna desc = %p, sts = %08x\n",
+ req->td_data, req->td_data->status);
+#endif
+ }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+ struct udc_request *req = NULL;
+ struct usb_request *_req = NULL;
+
+ /* alloc the dummy request */
+ _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+ if (_req) {
+ req = container_of(_req, struct udc_request, req);
+ ep->bna_dummy_req = req;
+ udc_init_bna_dummy(req);
+ }
+ return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+ u8 *req_buf;
+ u32 *buf;
+ int i, j;
+ unsigned bytes = 0;
+ unsigned remaining = 0;
+
+ if (!req || !ep)
+ return;
+
+ req_buf = req->buf + req->actual;
+ prefetch(req_buf);
+ remaining = req->length - req->actual;
+
+ buf = (u32 *) req_buf;
+
+ bytes = ep->ep.maxpacket;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ writel(*(buf + i), ep->txfifo);
+ }
+
+ /* remaining bytes must be written by byte access */
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+ ep->txfifo);
+ }
+
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+ int i;
+
+ VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+ for (i = 0; i < dwords; i++) {
+ *(buf + i) = readl(dev->rxfifo);
+ }
+ return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+ int i, j;
+ u32 tmp;
+
+ VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+ }
+
+ /* remaining bytes must be read by byte access */
+ if (bytes % UDC_DWORD_BYTES) {
+ tmp = readl(dev->rxfifo);
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+ tmp = tmp >> UDC_BITS_PER_BYTE;
+ }
+ }
+
+ return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+ u8 *buf;
+ unsigned buf_space;
+ unsigned bytes = 0;
+ unsigned finished = 0;
+
+ /* received number bytes */
+ bytes = readl(&ep->regs->sts);
+ bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+ buf_space = req->req.length - req->req.actual;
+ buf = req->req.buf + req->req.actual;
+ if (bytes > buf_space) {
+ if ((buf_space % ep->ep.maxpacket) != 0) {
+ DBG(ep->dev,
+ "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+ ep->ep.name, bytes, buf_space);
+ req->req.status = -EOVERFLOW;
+ }
+ bytes = buf_space;
+ }
+ req->req.actual += bytes;
+
+ /* last packet ? */
+ if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+ || ((req->req.actual == req->req.length) && !req->req.zero))
+ finished = 1;
+
+ /* read rx fifo bytes */
+ VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+ udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+ return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+ int retval = 0;
+ u32 tmp;
+
+ VDBG(ep->dev, "prep_dma\n");
+ VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+ ep->num, req->td_data);
+
+ /* set buffer pointer */
+ req->td_data->bufptr = req->req.dma;
+
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+ /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+ if (use_dma_ppb) {
+
+ retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+ if (retval != 0) {
+ if (retval == -ENOMEM)
+ DBG(ep->dev, "Out of DMA memory\n");
+ return retval;
+ }
+ if (ep->in) {
+ if (req->req.length == ep->ep.maxpacket) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+
+ }
+ }
+
+ }
+
+ if (ep->in) {
+ VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+ "maxpacket=%d ep%d\n",
+ use_dma_ppb, req->req.length,
+ ep->ep.maxpacket, ep->num);
+ /*
+ * if bytes < max packet then tx bytes must
+ * be written in packet per buffer mode
+ */
+ if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+ || ep->num == UDC_EP0OUT_IX
+ || ep->num == UDC_EP0IN_IX) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ req->req.length,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* reset frame num */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ 0,
+ UDC_DMA_IN_STS_FRAMENUM);
+ }
+ /* set HOST BUSY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ } else {
+ VDBG(ep->dev, "OUT set host ready\n");
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ }
+
+ return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+ struct udc *dev;
+ unsigned halted;
+
+ VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+ dev = ep->dev;
+ /* unmap DMA */
+ if (req->dma_mapping) {
+ if (ep->in)
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 0;
+ req->req.dma = DMA_DONT_USE;
+ }
+
+ halted = ep->halted;
+ ep->halted = 1;
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = sts;
+
+ /* remove from ep queue */
+ list_del_init(&req->queue);
+
+ VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+ &req->req, req->req.length, ep->ep.name, sts);
+
+ spin_unlock(&dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+ int ret_val = 0;
+ struct udc_data_dma *td;
+ struct udc_data_dma *td_last = NULL;
+ unsigned int i;
+
+ DBG(dev, "free chain req = %p\n", req);
+
+ /* do not free first desc., will be done by free for request */
+ td_last = req->td_data;
+ td = phys_to_virt(td_last->next);
+
+ for (i = 1; i < req->chain_len; i++) {
+
+ pci_pool_free(dev->data_requests, td,
+ (dma_addr_t) td_last->next);
+ td_last = td;
+ td = phys_to_virt(td_last->next);
+ }
+
+ return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+
+ td = req->td_data;
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ }
+
+ return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+ u32 count;
+
+ td = req->td_data;
+ /* received number bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ /* received number bytes */
+ if (td) {
+ count += AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ }
+ }
+
+ return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+ struct udc_ep *ep,
+ struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags
+)
+{
+ unsigned long bytes = req->req.length;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct udc_data_dma *td = NULL;
+ struct udc_data_dma *last = NULL;
+ unsigned long txbytes;
+ unsigned create_new_chain = 0;
+ unsigned len;
+
+ VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+ bytes, buf_len);
+ dma_addr = DMA_DONT_USE;
+
+ /* unset L bit in first desc for OUT */
+ if (!ep->in) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* alloc only new desc's if not already available */
+ len = req->req.length / ep->ep.maxpacket;
+ if (req->req.length % ep->ep.maxpacket) {
+ len++;
+ }
+
+ if (len > req->chain_len) {
+ /* shorter chain already allocated before */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = len;
+ create_new_chain = 1;
+ }
+
+ td = req->td_data;
+ /* gen. required number of descriptors and buffers */
+ for (i = buf_len; i < bytes; i += buf_len) {
+ /* create or determine next desc. */
+ if (create_new_chain) {
+
+ td = pci_pool_alloc(ep->dev->data_requests,
+ gfp_flags, &dma_addr);
+ if (!td)
+ return -ENOMEM;
+
+ td->status = 0;
+ } else if (i == buf_len) {
+ /* first td */
+ td = (struct udc_data_dma *) phys_to_virt(
+ req->td_data->next);
+ td->status = 0;
+ } else {
+ td = (struct udc_data_dma *) phys_to_virt(last->next);
+ td->status = 0;
+ }
+
+
+ if (td)
+ td->bufptr = req->req.dma + i; /* assign buffer */
+ else
+ break;
+
+ /* short packet ? */
+ if ((bytes - i) >= buf_len) {
+ txbytes = buf_len;
+ } else {
+ /* short packet */
+ txbytes = bytes - i;
+ }
+
+ /* link td and assign tx bytes */
+ if (i == buf_len) {
+ if (create_new_chain) {
+ req->td_data->next = dma_addr;
+ } else {
+ /* req->td_data->next = virt_to_phys(td); */
+ }
+ /* write tx bytes */
+ if (ep->in) {
+ /* first desc */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* second desc */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ } else {
+ if (create_new_chain) {
+ last->next = dma_addr;
+ } else {
+ /* last->next = virt_to_phys(td); */
+ }
+ if (ep->in) {
+ /* write tx bytes */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ }
+ last = td;
+ }
+ /* set last bit */
+ if (td) {
+ td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* last desc. points to itself */
+ req->td_data_last = td;
+ }
+
+ return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+ u32 tmp;
+
+ VDBG(dev, "udc_set_rde()\n");
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* set RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+ int retval = 0;
+ u8 open_rxfifo = 0;
+ unsigned long iflags;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc *dev;
+ u32 tmp;
+
+ /* check the inputs */
+ req = container_of(usbreq, struct udc_request, req);
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+ || !list_empty(&req->queue))
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+
+ VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+ dev = ep->dev;
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* map dma (usually done before) */
+ if (ep->dma && usbreq->length != 0
+ && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+ VDBG(dev, "DMA map req %p\n", req);
+ if (ep->in)
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_TODEVICE);
+ else
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 1;
+ }
+
+ VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+ usbep->name, usbreq, usbreq->length,
+ req->td_data, usbreq->buf);
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+
+ /* on empty queue just do first transfer */
+ if (list_empty(&ep->queue)) {
+ /* zlp */
+ if (usbreq->length == 0) {
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+ VDBG(dev, "%s: zlp\n", ep->ep.name);
+ /*
+ * if set_config or set_intf is waiting for ack by zlp
+ * then set CSR_DONE
+ */
+ if (dev->set_cfg_not_acked) {
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+ writel(tmp, &dev->regs->ctl);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (dev->waiting_zlp_ack_ep0in) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+ UDC_EP0IN_IX);
+ dev->waiting_zlp_ack_ep0in = 0;
+ }
+ goto finished;
+ }
+ if (ep->dma) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ /* write desc pointer to enable DMA */
+ if (ep->in) {
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+ }
+
+ /* disabled rx dma while descriptor update */
+ if (!ep->in) {
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* clear RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+ open_rxfifo = 1;
+
+ /*
+ * if BNA occurred then let BNA dummy desc.
+ * point to current desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "copy to BNA dummy desc.\n");
+ memcpy(ep->bna_dummy_req->td_data,
+ req->td_data,
+ sizeof(struct udc_data_dma));
+ }
+ }
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+ }
+
+ } else if (ep->dma) {
+
+ /*
+ * prep_dma not used for OUT ep's, this is not possible
+ * for PPB modes, because of chain creation reasons
+ */
+ if (ep->in) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ }
+ }
+ VDBG(dev, "list_add\n");
+ /* add request to ep queue */
+ if (req) {
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ /* open rxfifo if out data queued */
+ if (open_rxfifo) {
+ /* enable DMA */
+ req->dma_going = 1;
+ udc_set_rde(dev);
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 1;
+ }
+ /* stop OUT naking */
+ if (!ep->in) {
+ if (!use_dma && udc_rxfifo_pending) {
+ DBG(dev, "udc_queue(): pending bytes in"
+ "rxfifo after nyet\n");
+ /*
+ * read pending bytes afer nyet:
+ * referring to isr
+ */
+ if (udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req(ep, req, 0);
+ }
+ udc_rxfifo_pending = 0;
+
+ }
+ }
+ }
+
+finished:
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+ struct udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ complete_req(ep, req, -ESHUTDOWN);
+ }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned halted;
+ unsigned long iflags;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ && ep->num != UDC_EP0OUT_IX)))
+ return -EINVAL;
+
+ req = container_of(usbreq, struct udc_request, req);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ halted = ep->halted;
+ ep->halted = 1;
+ /* request in processing or next one */
+ if (ep->queue.next == &req->queue) {
+ if (ep->dma && req->dma_going) {
+ if (ep->in)
+ ep->cancel_transfer = 1;
+ else {
+ u32 tmp;
+ u32 dma_sts;
+ /* stop potential receive DMA */
+ tmp = readl(&udc->regs->ctl);
+ writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+ &udc->regs->ctl);
+ /*
+ * Cancel transfer later in ISR
+ * if descriptor was touched.
+ */
+ dma_sts = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+ ep->cancel_transfer = 1;
+ else {
+ udc_init_bna_dummy(ep->req);
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ }
+ writel(tmp, &udc->regs->ctl);
+ }
+ }
+ }
+ complete_req(ep, req, -ECONNRESET);
+ ep->halted = halted;
+
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+ return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ unsigned long iflags;
+ int retval = 0;
+
+ if (!usbep)
+ return -EINVAL;
+
+ pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ /* halt or clear halt */
+ if (halt) {
+ if (ep->num == 0)
+ ep->dev->stall_ep0in = 1;
+ else {
+ /*
+ * set STALL
+ * rxfifo empty not taken into acount
+ */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 1;
+
+ /* setup poll timer */
+ if (!timer_pending(&udc_pollstall_timer)) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ if (!stop_pollstall_timer) {
+ DBG(ep->dev, "start polltimer\n");
+ add_timer(&udc_pollstall_timer);
+ }
+ }
+ }
+ } else {
+ /* ep is halted by set_halt() before */
+ if (ep->halted) {
+ tmp = readl(&ep->regs->ctl);
+ /* clear stall bit */
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+ .enable = udc_ep_enable,
+ .disable = udc_ep_disable,
+
+ .alloc_request = udc_alloc_request,
+ .free_request = udc_free_request,
+
+ .queue = udc_queue,
+ .dequeue = udc_dequeue,
+
+ .set_halt = udc_set_halt,
+ /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+ struct udc *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct udc, gadget);
+ udc_remote_wakeup(dev);
+
+ return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+ .wakeup = udc_wakeup,
+ .get_frame = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+ /* make gadget ep lists */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+
+ /* fifo config */
+ dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+ dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+ u32 tmp;
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+
+ /* program speed */
+ tmp = readl(&dev->regs->cfg);
+ if (use_fullspeed) {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ } else {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+ }
+ writel(tmp, &dev->regs->cfg);
+
+ return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_basic_init()\n");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop poll stall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+ writel(tmp, &dev->regs->ctl);
+
+ /* enable dynamic CSR programming */
+ tmp = readl(&dev->regs->cfg);
+ tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+ /* set self powered */
+ tmp |= AMD_BIT(UDC_DEVCFG_SP);
+ /* set remote wakeupable */
+ tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+ writel(tmp, &dev->regs->cfg);
+
+ make_ep_lists(dev);
+
+ dev->data_ep_enabled = 0;
+ dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ u32 reg;
+
+ DBG(dev, "udc_setup_endpoints()\n");
+
+ /* read enum speed */
+ tmp = readl(&dev->regs->sts);
+ tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ dev->gadget.speed = USB_SPEED_HIGH;
+ } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ /* set basic ep parameters */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ ep = &dev->ep[tmp];
+ ep->dev = dev;
+ ep->ep.name = ep_string[tmp];
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ } else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+ ep->regs = &dev->ep_regs[tmp];
+ /*
+ * ep will be reset only if ep was not enabled before to avoid
+ * disabling ep interrupts when ENUM interrupt occurs but ep is
+ * not enabled by gadget driver
+ */
+ if (!ep->desc) {
+ ep_init(dev->regs, ep);
+ }
+
+ if (use_dma) {
+ /*
+ * ep->dma is not really used, just to indicate that
+ * DMA is active: remove this
+ * dma regs = dev control regs
+ */
+ ep->dma = &dev->regs->ctl;
+
+ /* nak OUT endpoints until enable - not for ep0 */
+ if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+ && tmp > UDC_EPIN_NUM) {
+ /* set NAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 1;
+
+ }
+ }
+ }
+ /* EP0 max packet */
+ if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+ UDC_FS_EP0OUT_MAX_PKT_SIZE;
+ } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+
+ /*
+ * with suspend bug workaround, ep0 params for gadget driver
+ * are set at gadget driver bind() call
+ */
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ dev->ep[UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+ /* init cfg/alt/int */
+ dev->cur_config = 0;
+ dev->cur_intf = 0;
+ dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Connect\n");
+
+ dev->connected = 1;
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+ dev->connected = 0;
+
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* REVISIT there doesn't seem to be a point to having this
+ * talk to a tasklet ... do it directly, we already hold
+ * the spinlock needed to process the disconnect.
+ */
+
+ tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+ struct udc *dev = (struct udc *)(*((struct udc **) par));
+ u32 tmp;
+
+ DBG(dev, "Tasklet disconnect\n");
+ spin_lock_irq(&dev->lock);
+
+ if (dev->driver) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* empty queues */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ }
+
+ /* disable ep0 */
+ ep_init(dev->regs,
+ &dev->ep[UDC_EP0IN_IX]);
+
+
+ if (!soft_reset_occured) {
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+ soft_reset_occured++;
+ }
+
+ /* re-enable dev interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+ /* back to full speed ? */
+ if (use_fullspeed) {
+ tmp = readl(&dev->regs->cfg);
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ writel(tmp, &dev->regs->cfg);
+ }
+
+ spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+ unsigned long flags;
+
+ DBG(dev, "Soft reset\n");
+ /*
+ * reset possible waiting interrupts, because int.
+ * status is lost after soft reset,
+ * ep int. status reset
+ */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+ /* device int. status reset */
+ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+ spin_lock_irqsave(&udc_irq_spinlock, flags);
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ readl(&dev->regs->cfg);
+ spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+ u32 tmp;
+
+ spin_lock_irq(&udc_irq_spinlock);
+
+ if (set_rde > 0) {
+ /*
+ * open the fifo if fifo was filled on last timer call
+ * conditionally
+ */
+ if (set_rde > 1) {
+ /* set RDE to receive setup data */
+ tmp = readl(&udc->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &udc->regs->ctl);
+ set_rde = -1;
+ } else if (readl(&udc->regs->sts)
+ & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ /*
+ * if fifo empty setup polling, do not just
+ * open the fifo
+ */
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ } else {
+ /*
+ * fifo contains data now, setup timer for opening
+ * the fifo when timer expires to be able to receive
+ * setup packets, when data packets gets queued by
+ * gadget layer then timer will forced to expire with
+ * set_rde=0 (RDE is set in udc_queue())
+ */
+ set_rde++;
+ /* debug: lhadmot_timer_start = 221070 */
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+
+ } else
+ set_rde = -1; /* RDE was set by udc_queue() */
+ spin_unlock_irq(&udc_irq_spinlock);
+ if (stop_timer)
+ complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+ u32 tmp;
+ /* set stall as long not halted */
+ if (ep->halted == 1) {
+ tmp = readl(&ep->regs->ctl);
+ /* STALL cleared ? */
+ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+ /*
+ * FIXME: MSC spec requires that stall remains
+ * even on receivng of CLEAR_FEATURE HALT. So
+ * we would set STALL again here to be compliant.
+ * But with current mass storage drivers this does
+ * not work (would produce endless host retries).
+ * So we clear halt on CLEAR_FEATURE.
+ *
+ DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);*/
+
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+ struct udc_ep *ep;
+ int halted = 0;
+
+ spin_lock_irq(&udc_stall_spinlock);
+ /*
+ * only one IN and OUT endpoints are handled
+ * IN poll stall
+ */
+ ep = &udc->ep[UDC_EPIN_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+ /* OUT poll stall */
+ ep = &udc->ep[UDC_EPOUT_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+
+ /* setup timer again when still halted */
+ if (!stop_pollstall_timer && halted) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ add_timer(&udc_pollstall_timer);
+ }
+ spin_unlock_irq(&udc_stall_spinlock);
+
+ if (stop_pollstall_timer)
+ complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "activate_control_endpoints\n");
+
+ /* flush fifo */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* set ep0 directions */
+ dev->ep[UDC_EP0IN_IX].in = 1;
+ dev->ep[UDC_EP0OUT_IX].in = 0;
+
+ /* set buffer size (tx fifo entries) of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+ /* set max packet size of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0_OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0 in UDC CSR */
+ tmp = readl(&dev->csr->ne[0]);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[0]);
+
+ if (use_dma) {
+ dev->ep[UDC_EP0OUT_IX].td->status |=
+ AMD_BIT(UDC_DMA_OUT_STS_L);
+ /* write dma desc address */
+ writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+ &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop pollstall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* enable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+ | AMD_BIT(UDC_DEVCTL_RDE)
+ | AMD_BIT(UDC_DEVCTL_TDE);
+ if (use_dma_bufferfill_mode) {
+ tmp |= AMD_BIT(UDC_DEVCTL_BF);
+ } else if (use_dma_ppb_du) {
+ tmp |= AMD_BIT(UDC_DEVCTL_DU);
+ }
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ /* clear NAK by writing CNAK for EP0IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* clear NAK by writing CNAK for EP0OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+ activate_control_endpoints(dev);
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!driver || !driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_HIGH)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ driver->driver.bus = NULL;
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ retval = driver->bind(&dev->gadget);
+
+ /* Some gadget drivers use both ep0 directions.
+ * NOTE: to gadget driver, ep0 is just one endpoint...
+ */
+ dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+ dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+ if (retval) {
+ DBG(dev, "binding to %s returning %d\n",
+ driver->driver.name, retval);
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ /* get ready for ep0 traffic */
+ setup_ep0(dev);
+
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ usb_connect(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ int tmp;
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ /* init */
+ udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ unsigned long flags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ udc_mask_unused_interrupts(dev);
+ shutdown(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+ dev->driver = NULL;
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+
+ DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+ u32 tmp;
+ u32 reg;
+
+ /* check epin's */
+ DBG(dev, "CNAK pending queue processing\n");
+ for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+ if (cnak_pending & (1 << tmp)) {
+ DBG(dev, "CNAK pending for ep%d\n", tmp);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+ }
+ }
+ /* ... and ep0out */
+ if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+ DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+ dev->ep[UDC_EP0OUT_IX].num);
+ }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+ if (use_dma) {
+ /*
+ * only enable RXDMA when no data endpoint enabled
+ * or data is queued
+ */
+ if (!dev->data_ep_enabled || dev->data_ep_queued) {
+ udc_set_rde(dev);
+ } else {
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data endpoints to early)
+ */
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies + HZ/UDC_RDE_TIMER_DIV;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+ }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned int count;
+ struct udc_data_dma *td = NULL;
+ unsigned dma_done;
+
+ VDBG(dev, "ep%d irq\n", ep_ix);
+ ep = &dev->ep[ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+ ep->num, readl(&ep->regs->desptr));
+ /* clear BNA */
+ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ if (!ep->cancel_transfer)
+ ep->bna_occurred = 1;
+ else
+ ep->cancel_transfer = 0;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ if (!list_empty(&ep->queue)) {
+
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else {
+ req = NULL;
+ udc_rxfifo_pending = 1;
+ }
+ VDBG(dev, "req = %p\n", req);
+ /* fifo mode */
+ if (!use_dma) {
+
+ /* read fifo */
+ if (req && udc_rxfifo_read(ep, req)) {
+ ret_val = IRQ_HANDLED;
+
+ /* finish */
+ complete_req(ep, req, 0);
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else
+ req = NULL;
+ }
+
+ /* DMA */
+ } else if (!ep->cancel_transfer && req != NULL) {
+ ret_val = IRQ_HANDLED;
+
+ /* check for DMA done */
+ if (!use_dma_ppb) {
+ dma_done = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ /*
+ * if BNA occurred then recover desc. from
+ * BNA dummy desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "Recover desc. from BNA dummy\n");
+ memcpy(req->td_data, ep->bna_dummy_req->td_data,
+ sizeof(struct udc_data_dma));
+ ep->bna_occurred = 0;
+ udc_init_bna_dummy(ep->req);
+ }
+ td = udc_get_last_dma_desc(req);
+ dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+ }
+ if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+ /* buffer fill mode - rx bytes */
+ if (!use_dma_ppb) {
+ /* received number bytes */
+ count = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ VDBG(dev, "rx bytes=%u\n", count);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ VDBG(dev, "req->td_data=%p\n", req->td_data);
+ VDBG(dev, "last desc = %p\n", td);
+ /* received number bytes */
+ if (use_dma_ppb_du) {
+ /* every desc. counts bytes */
+ count = udc_get_ppbdu_rxbytes(req);
+ } else {
+ /* last desc. counts bytes */
+ count = AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ if (!count && req->req.length
+ == UDC_DMA_MAXPACKET) {
+ /*
+ * on 64k packets the RXBYTES
+ * field is zero
+ */
+ count = UDC_DMA_MAXPACKET;
+ }
+ }
+ VDBG(dev, "last desc rx bytes=%u\n", count);
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ DBG(dev, "%s: rx %db, space=%db\n",
+ ep->ep.name, count, tmp);
+ req->req.status = -EOVERFLOW;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+ req->dma_going = 0;
+ /* complete request */
+ complete_req(ep, req, 0);
+
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ /*
+ * DMA may be already started by udc_queue()
+ * called by gadget drivers completion
+ * routine. This happens when queue
+ * holds one request only.
+ */
+ if (req->dma_going == 0) {
+ /* next dma */
+ if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+ goto finished;
+ /* write desc pointer */
+ writel(req->td_phys,
+ &ep->regs->desptr);
+ req->dma_going = 1;
+ /* enable DMA */
+ udc_set_rde(dev);
+ }
+ } else {
+ /*
+ * implant BNA dummy descriptor to allow
+ * RXFIFO opening by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ /*
+ * schedule timer for setting RDE if queue
+ * remains empty to allow ep0 packets pass
+ * through
+ */
+ if (set_rde != 0
+ && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies
+ + HZ*UDC_RDE_TIMER_SECONDS;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 0;
+ }
+
+ } else {
+ /*
+ * RX DMA must be reenabled for each desc in PPBDU mode
+ * and must be enabled for PPBNDU mode in case of BNA
+ */
+ udc_set_rde(dev);
+ }
+
+ } else if (ep->cancel_transfer) {
+ ret_val = IRQ_HANDLED;
+ ep->cancel_transfer = 0;
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 epsts;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc_data_dma *td;
+ unsigned dma_done;
+ unsigned len;
+
+ ep = &dev->ep[ep_ix];
+
+ epsts = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+ dev_err(&dev->pdev->dev,
+ "BNA ep%din occured - DESPTR = %08lx \n",
+ ep->num,
+ (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(epsts, &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev,
+ "HE ep%dn occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear HE */
+ writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* DMA completion */
+ if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "TDC set- completion\n");
+ ret_val = IRQ_HANDLED;
+ if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ if (req) {
+ /*
+ * length bytes transfered
+ * check dma done of last desc. in PPBDU mode
+ */
+ if (use_dma_ppb_du) {
+ td = udc_get_last_dma_desc(req);
+ if (td) {
+ dma_done =
+ AMD_GETBITS(td->status,
+ UDC_DMA_IN_STS_BS);
+ /* don't care DMA done */
+ req->req.actual =
+ req->req.length;
+ }
+ } else {
+ /* assume all bytes transferred */
+ req->req.actual = req->req.length;
+ }
+
+ if (req->req.actual == req->req.length) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+ /* further request available ? */
+ if (list_empty(&ep->queue)) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
+ }
+
+ }
+ }
+ }
+ ep->cancel_transfer = 0;
+
+ }
+ /*
+ * status reg has IN bit set and TDC not set (if TDC was handled,
+ * IN must not be handled (UDC defect) ?
+ */
+ if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+ && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+ ret_val = IRQ_HANDLED;
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ /* FIFO mode */
+ if (!use_dma) {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ /* DMA */
+ } else if (req && !req->dma_going) {
+ VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+ req, req->td_data);
+ if (req->td_data) {
+
+ req->dma_going = 1;
+
+ /*
+ * unset L bit of first desc.
+ * for chain
+ */
+ if (use_dma_ppb && req->req.length >
+ ep->ep.maxpacket) {
+ req->td_data->status &=
+ AMD_CLEAR_BIT(
+ UDC_DMA_IN_STS_L);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+
+ /* set poll demand bit */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+
+ }
+ }
+ /* clear status bits */
+ writel(epsts, &ep->regs->sts);
+
+finished:
+ return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ int setup_supported;
+ u32 count;
+ int set = 0;
+ struct udc_ep *ep;
+ struct udc_ep *ep_tmp;
+
+ ep = &dev->ep[UDC_EP0OUT_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ /* check BNA and clear if set */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ VDBG(dev, "ep0: BNA set\n");
+ writel(AMD_BIT(UDC_EPSTS_BNA),
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ ep->bna_occurred = 1;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* type of data: SETUP or DATA 0 bytes */
+ tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+ VDBG(dev, "data_typ = %x\n", tmp);
+
+ /* setup data */
+ if (tmp == UDC_EPSTS_OUT_SETUP) {
+ ret_val = IRQ_HANDLED;
+
+ ep->dev->stall_ep0in = 0;
+ dev->waiting_zlp_ack_ep0in = 0;
+
+ /* set NAK for EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 1;
+ /* get setup data */
+ if (use_dma) {
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ setup_data.data[0] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+ setup_data.data[1] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td_stp->status =
+ UDC_DMA_STP_STS_BS_HOST_READY;
+ } else {
+ /* read fifo */
+ udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+ }
+
+ /* determine direction of control data */
+ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ set = 0;
+ } else {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+ /*
+ * implant BNA dummy descriptor to allow RXFIFO opening
+ * by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ set = 1;
+ dev->ep[UDC_EP0OUT_IX].naking = 1;
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data to early)
+ */
+ set_rde = 1;
+ if (!timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies +
+ HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+
+ /*
+ * mass storage reset must be processed here because
+ * next packet may be a CLEAR_FEATURE HALT which would not
+ * clear the stall bit when no STALL handshake was received
+ * before (autostall can cause this)
+ */
+ if (setup_data.data[0] == UDC_MSCRES_DWORD0
+ && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+ DBG(dev, "MSC Reset\n");
+ /*
+ * clear stall bits
+ * only one IN and OUT endpoints are handled
+ */
+ ep_tmp = &udc->ep[UDC_EPIN_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ ep_tmp = &udc->ep[UDC_EPOUT_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ }
+
+ /* call gadget with setup data received */
+ spin_unlock(&dev->lock);
+ setup_supported = dev->driver->setup(&dev->gadget,
+ &setup_data.request);
+ spin_lock(&dev->lock);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ /* ep0 in returns data (not zlp) on IN phase */
+ if (setup_supported >= 0 && setup_supported <
+ UDC_EP0IN_MAXPACKET) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* if unsupported request then stall */
+ } else if (setup_supported < 0) {
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ } else
+ dev->waiting_zlp_ack_ep0in = 1;
+
+
+ /* clear NAK by writing CNAK in EP0_OUT */
+ if (!set) {
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+ }
+
+ if (!use_dma) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ /* data packet 0 bytes */
+ } else if (tmp == UDC_EPSTS_OUT_DATA) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ /* get setup data: only 0 packet */
+ if (use_dma) {
+ /* no req if 0 packet, just reactivate */
+ if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+ VDBG(dev, "ZLP\n");
+
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td->status =
+ AMD_ADDBITS(
+ dev->ep[UDC_EP0OUT_IX].td->status,
+ UDC_DMA_OUT_STS_BS_HOST_READY,
+ UDC_DMA_OUT_STS_BS);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ ret_val = IRQ_HANDLED;
+
+ } else {
+ /* control write */
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ /* re-program desc. pointer for possible ZLPs */
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ } else {
+
+ /* received number bytes */
+ count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+ /* out data for fifo mode not working */
+ count = 0;
+
+ /* 0 packet or real data ? */
+ if (count != 0) {
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ } else {
+ /* dummy read confirm */
+ readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+ ret_val = IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned len;
+
+ ep = &dev->ep[UDC_EP0IN_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "isr: TDC clear \n");
+ ret_val = IRQ_HANDLED;
+
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+ /* status reg has IN bit set ? */
+ } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ ret_val = IRQ_HANDLED;
+
+ if (ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ if (dev->stall_ep0in) {
+ DBG(dev, "stall ep0in\n");
+ /* halt ep0in */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ } else {
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+
+ if (ep->dma) {
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+ /* set poll demand bit */
+ tmp =
+ readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp,
+ &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* all bytes will be transferred */
+ req->req.actual = req->req.length;
+
+ /* complete req */
+ complete_req(ep, req, 0);
+
+ } else {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+
+ /* lengh bytes transfered */
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ }
+
+ }
+ }
+ ep->halted = 0;
+ dev->stall_ep0in = 0;
+ if (!ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ }
+
+ return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 cfg;
+ struct udc_ep *ep;
+ u16 i;
+ u8 udc_csr_epix;
+
+ /* SET_CONFIG irq ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+ ret_val = IRQ_HANDLED;
+
+ /* read config value */
+ tmp = readl(&dev->regs->sts);
+ cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+ DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+ dev->cur_config = cfg;
+ dev->set_cfg_not_acked = 1;
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.request.wValue = dev->cur_config;
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep cfg */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+ UDC_CSR_NE_CFG);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* SET_INTERFACE ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+ ret_val = IRQ_HANDLED;
+
+ dev->set_cfg_not_acked = 1;
+ /* read interface and alt setting values */
+ tmp = readl(&dev->regs->sts);
+ dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+ dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+ setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+ setup_data.request.wValue = dev->cur_alt;
+ setup_data.request.wIndex = dev->cur_intf;
+
+ DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+ dev->cur_alt, dev->cur_intf);
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ /* UDC CSR reg */
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+ UDC_CSR_NE_INTF);
+ /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+ UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* USB reset */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+ DBG(dev, "USB Reset interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* allow soft reset when suspend occurs */
+ soft_reset_occured = 0;
+
+ dev->waiting_zlp_ack_ep0in = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* call gadget to resume and reset configs etc. */
+ spin_unlock(&dev->lock);
+ if (dev->sys_suspended && dev->driver->resume) {
+ dev->driver->resume(&dev->gadget);
+ dev->sys_suspended = 0;
+ }
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* soft reset when rxfifo not empty */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+ && !soft_reset_after_usbreset_occured) {
+ udc_soft_reset(dev);
+ soft_reset_after_usbreset_occured++;
+ }
+
+ /*
+ * DMA reset to kill potential old DMA hw hang,
+ * POLL bit is already reset by ep_init() through
+ * disconnect()
+ */
+ DBG(dev, "DMA machine reset\n");
+ tmp = readl(&dev->regs->cfg);
+ writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+ writel(tmp, &dev->regs->cfg);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ /* enable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+
+ } /* USB suspend */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+ DBG(dev, "USB Suspend interrupt\n");
+ ret_val = IRQ_HANDLED;
+ if (dev->driver->suspend) {
+ spin_unlock(&dev->lock);
+ dev->sys_suspended = 1;
+ dev->driver->suspend(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ } /* new speed ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+ DBG(dev, "ENUM interrupt\n");
+ ret_val = IRQ_HANDLED;
+ soft_reset_after_usbreset_occured = 0;
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+ if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "high");
+ } else if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "full");
+ }
+
+ /* init ep 0 */
+ activate_control_endpoints(dev);
+
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ }
+ /* session valid change interrupt */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+ DBG(dev, "USB SVC interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* check that session is not valid to detect disconnect */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+ /* disable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp |= AMD_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+ DBG(dev, "USB Disconnect (session valid low)\n");
+ /* cleanup on disconnect */
+ usb_disconnect(udc);
+ }
+
+ }
+
+ return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+ struct udc *dev = pdev;
+ u32 reg;
+ u16 i;
+ u32 ep_irq;
+ irqreturn_t ret_val = IRQ_NONE;
+
+ spin_lock(&dev->lock);
+
+ /* check for ep irq */
+ reg = readl(&dev->regs->ep_irqsts);
+ if (reg) {
+ if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+ ret_val |= udc_control_out_isr(dev);
+ if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+ ret_val |= udc_control_in_isr(dev);
+
+ /*
+ * data endpoint
+ * iterate ep's
+ */
+ for (i = 1; i < UDC_EP_NUM; i++) {
+ ep_irq = 1 << i;
+ if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+ continue;
+
+ /* clear irq status */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+
+ /* irq for out ep ? */
+ if (i > UDC_EPIN_NUM)
+ ret_val |= udc_data_out_isr(dev, i);
+ else
+ ret_val |= udc_data_in_isr(dev, i);
+ }
+
+ }
+
+
+ /* check for dev irq */
+ reg = readl(&dev->regs->irqsts);
+ if (reg) {
+ /* clear irq */
+ writel(reg, &dev->regs->irqsts);
+ ret_val |= udc_dev_isr(dev, reg);
+ }
+
+
+ spin_unlock(&dev->lock);
+ return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+ struct amd5536udc *dev = dev_get_drvdata(pdev);
+ kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+ /* remove timer */
+ stop_timer++;
+ if (timer_pending(&udc_timer))
+ wait_for_completion(&on_exit);
+ if (udc_timer.data)
+ del_timer_sync(&udc_timer);
+ /* remove pollstall timer */
+ stop_pollstall_timer++;
+ if (timer_pending(&udc_pollstall_timer))
+ wait_for_completion(&on_pollstall_exit);
+ if (udc_pollstall_timer.data)
+ del_timer_sync(&udc_pollstall_timer);
+ udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+ struct udc *dev;
+
+ dev = pci_get_drvdata(pdev);
+
+ /* gadget driver must not be registered */
+ BUG_ON(dev->driver != NULL);
+
+ /* dma pool cleanup */
+ if (dev->data_requests)
+ pci_pool_destroy(dev->data_requests);
+
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td_stp,
+ dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td,
+ dev->ep[UDC_EP0OUT_IX].td_phys);
+
+ pci_pool_destroy(dev->stp_requests);
+ }
+
+ /* reset controller */
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ if (dev->irq_registered)
+ free_irq(pdev->irq, dev);
+ if (dev->regs)
+ iounmap(dev->regs);
+ if (dev->mem_region)
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (dev->active)
+ pci_disable_device(pdev);
+
+ device_unregister(&dev->gadget.dev);
+ pci_set_drvdata(pdev, NULL);
+
+ udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td_data;
+ int retval;
+
+ /* consistent DMA mode setting ? */
+ if (use_dma_ppb) {
+ use_dma_bufferfill_mode = 0;
+ } else {
+ use_dma_ppb_du = 0;
+ use_dma_bufferfill_mode = 1;
+ }
+
+ /* DMA setup */
+ dev->data_requests = dma_pool_create("data_requests", NULL,
+ sizeof(struct udc_data_dma), 0, 0);
+ if (!dev->data_requests) {
+ DBG(dev, "can't get request data pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* EP0 in dma regs = dev control regs */
+ dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+ /* dma desc for setup data */
+ dev->stp_requests = dma_pool_create("setup requests", NULL,
+ sizeof(struct udc_stp_dma), 0, 0);
+ if (!dev->stp_requests) {
+ DBG(dev, "can't get stp request pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+ /* setup */
+ td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ if (td_stp == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+ /* data: 0 packets !? */
+ td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_phys);
+ if (td_data == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td = td_data;
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+ struct pci_dev *pdev,
+ const struct pci_device_id *id
+)
+{
+ struct udc *dev;
+ unsigned long resource;
+ unsigned long len;
+ int retval = 0;
+
+ /* one udc only */
+ if (udc) {
+ dev_dbg(&pdev->dev, "already probed\n");
+ return -EBUSY;
+ }
+
+ /* init */
+ dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ memset(dev, 0, sizeof(struct udc));
+
+ /* pci setup */
+ if (pci_enable_device(pdev) < 0) {
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev->active = 1;
+
+ /* PCI resource allocation */
+ resource = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+
+ if (!request_mem_region(resource, len, name)) {
+ dev_dbg(&pdev->dev, "pci device used already\n");
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->mem_region = 1;
+
+ dev->virt_addr = ioremap_nocache(resource, len);
+ if (dev->virt_addr == NULL) {
+ dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+ retval = -EFAULT;
+ goto finished;
+ }
+
+ if (!pdev->irq) {
+ dev_err(&dev->pdev->dev, "irq not set\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+
+ if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+ dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->irq_registered = 1;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* chip revision */
+ dev->chiprev = 0;
+
+ pci_set_master(pdev);
+ pci_set_mwi(pdev);
+
+ /* chip rev for Hs AMD5536 */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+ /* init dma pools */
+ if (use_dma) {
+ retval = init_dma_pools(dev);
+ if (retval != 0)
+ goto finished;
+ }
+
+ dev->phys_addr = resource;
+ dev->irq = pdev->irq;
+ dev->pdev = pdev;
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ /* general probing */
+ if (udc_probe(dev) == 0)
+ return 0;
+
+finished:
+ if (dev)
+ udc_pci_remove(pdev);
+ return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+ char tmp[128];
+ u32 reg;
+ int retval;
+
+ /* mark timer as not initialized */
+ udc_timer.data = 0;
+ udc_pollstall_timer.data = 0;
+
+ /* device struct setup */
+ spin_lock_init(&dev->lock);
+ dev->gadget.ops = &udc_ops;
+
+ strcpy(dev->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+ dev->gadget.name = name;
+ dev->gadget.is_dualspeed = 1;
+
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+ /* init registers, interrupts, ... */
+ startup_registers(dev);
+
+ dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+ snprintf(tmp, sizeof tmp, "%d", dev->irq);
+ dev_info(&dev->pdev->dev,
+ "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+ tmp, dev->phys_addr, dev->chiprev,
+ (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+ strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+ if (dev->chiprev == UDC_HSA0_REV) {
+ dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev_info(&dev->pdev->dev,
+ "driver version: %s(for Geode5536 B1)\n", tmp);
+ udc = dev;
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval)
+ goto finished;
+
+ /* timer init */
+ init_timer(&udc_timer);
+ udc_timer.function = udc_timer_function;
+ udc_timer.data = 1;
+ /* timer pollstall init */
+ init_timer(&udc_pollstall_timer);
+ udc_pollstall_timer.function = udc_pollstall_timer_function;
+ udc_pollstall_timer.data = 1;
+
+ /* set SD */
+ reg = readl(&dev->regs->ctl);
+ reg |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(reg, &dev->regs->ctl);
+
+ /* print dev register info */
+ print_regs(dev);
+
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ DBG(dev, "UDC initiates remote wakeup\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+ tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+ .name = (char *) name,
+ .id_table = pci_id,
+ .probe = udc_pci_probe,
+ .remove = udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+ return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+ pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 00000000000..4bbabbbfc93
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS 1
+#define UDC_RDE_TIMER_DIV 10
+#define UDC_POLLSTALL_TIMER_USECONDS 500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0 0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16
+
+#define UDC_SETCONFIG_DWORD1 0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0 0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS 16
+
+#define UDC_SETINTF_DWORD1 0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS 0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0 0x0000ff21
+#define UDC_MSCRES_DWORD1 0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR 0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_NUM_OFS 0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_DIR_OFS 4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_TYPE_OFS 5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_CFG_OFS 7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_INTF_OFS 11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_ALT_OFS 15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR 0x400
+
+#define UDC_DEVCFG_SOFTRESET 31
+#define UDC_DEVCFG_HNPSFEN 30
+#define UDC_DEVCFG_DMARST 29
+#define UDC_DEVCFG_SET_DESC 18
+#define UDC_DEVCFG_CSR_PRG 17
+#define UDC_DEVCFG_STATUS 7
+#define UDC_DEVCFG_DIR 6
+#define UDC_DEVCFG_PI 5
+#define UDC_DEVCFG_SS 4
+#define UDC_DEVCFG_SP 3
+#define UDC_DEVCFG_RWKP 2
+
+#define UDC_DEVCFG_SPD_MASK 0x3
+#define UDC_DEVCFG_SPD_OFS 0
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+/*#define UDC_DEVCFG_SPD_FS 0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR 0x404
+
+#define UDC_DEVCTL_THLEN_MASK 0xff000000
+#define UDC_DEVCTL_THLEN_OFS 24
+
+#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS 16
+
+#define UDC_DEVCTL_CSR_DONE 13
+#define UDC_DEVCTL_DEVNAK 12
+#define UDC_DEVCTL_SD 10
+#define UDC_DEVCTL_MODE 9
+#define UDC_DEVCTL_BREN 8
+#define UDC_DEVCTL_THE 7
+#define UDC_DEVCTL_BF 6
+#define UDC_DEVCTL_BE 5
+#define UDC_DEVCTL_DU 4
+#define UDC_DEVCTL_TDE 3
+#define UDC_DEVCTL_RDE 2
+#define UDC_DEVCTL_RES 0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR 0x408
+
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_TS_OFS 18
+
+#define UDC_DEVSTS_SESSVLD 17
+#define UDC_DEVSTS_PHY_ERROR 16
+#define UDC_DEVSTS_RXFIFO_EMPTY 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS 13
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+
+#define UDC_DEVSTS_SUSP 12
+
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_ALT_OFS 8
+
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_INTF_OFS 4
+
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+#define UDC_DEVSTS_CFG_OFS 0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR 0x40c
+
+#define UDC_DEVINT_SVC 7
+#define UDC_DEVINT_ENUM 6
+#define UDC_DEVINT_SOF 5
+#define UDC_DEVINT_US 4
+#define UDC_DEVINT_UR 3
+#define UDC_DEVINT_ES 2
+#define UDC_DEVINT_SI 1
+#define UDC_DEVINT_SC 0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR 0x410
+
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR 0x414
+
+#define UDC_EPINT_OUT_MASK 0xffff0000
+#define UDC_EPINT_OUT_OFS 16
+#define UDC_EPINT_IN_MASK 0x0000ffff
+#define UDC_EPINT_IN_OFS 0
+
+#define UDC_EPINT_IN_EP0 0
+#define UDC_EPINT_IN_EP1 1
+#define UDC_EPINT_IN_EP2 2
+#define UDC_EPINT_IN_EP3 3
+#define UDC_EPINT_OUT_EP0 16
+#define UDC_EPINT_OUT_EP1 17
+#define UDC_EPINT_OUT_EP2 18
+#define UDC_EPINT_OUT_EP3 19
+
+#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR 0x418
+
+#define UDC_EPINT_OUT_MSK_MASK 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS 16
+#define UDC_EPINT_IN_MSK_MASK 0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS 0
+
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE 0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR 0x0
+#define UDC_EPIN_REGS_ADDR 0x0
+#define UDC_EPOUT_REGS_ADDR 0x200
+
+#define UDC_EPCTL_ADDR 0x0
+
+#define UDC_EPCTL_RRDY 9
+#define UDC_EPCTL_CNAK 8
+#define UDC_EPCTL_SNAK 7
+#define UDC_EPCTL_NAK 6
+
+#define UDC_EPCTL_ET_MASK 0x00000030
+#define UDC_EPCTL_ET_OFS 4
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+#define UDC_EPCTL_P 3
+#define UDC_EPCTL_SN 2
+#define UDC_EPCTL_F 1
+#define UDC_EPCTL_S 0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR 0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS 11
+
+#define UDC_EPSTS_TDC 10
+#define UDC_EPSTS_HE 9
+#define UDC_EPSTS_BNA 7
+#define UDC_EPSTS_IN 6
+
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_OUT_OFS 4
+#define UDC_EPSTS_OUT_DATA 1
+#define UDC_EPSTS_OUT_DATA_CLEAR 0x10
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20
+#define UDC_EPSTS_OUT_CLEAR 0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE 32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE 256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE 32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE 32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS 0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS 16
+#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE 64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS 16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS 20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS 24
+#define UDC_DMA_STP_STS_RX_MASK 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS 28
+#define UDC_DMA_STP_STS_BS_MASK 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS 30
+#define UDC_DMA_STP_STS_BS_HOST_READY 0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY 1
+#define UDC_DMA_STP_STS_BS_DMA_DONE 2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY 3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS 0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS 0
+#define UDC_DMA_IN_STS_L 27
+#define UDC_DMA_IN_STS_TX_MASK 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS 28
+#define UDC_DMA_IN_STS_BS_MASK 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS 30
+#define UDC_DMA_IN_STS_BS_HOST_READY 0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY 1
+#define UDC_DMA_IN_STS_BS_DMA_DONE 2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY 3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS 0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0
+#define UDC_DMA_OUT_STS_L 27
+#define UDC_DMA_OUT_STS_RX_MASK 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS 28
+#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY 0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE 2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET 1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET 65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR 0x10
+#define UDC_EP_DESPTR_ADDR 0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM 32
+#define UDC_EPIN_NUM 16
+#define UDC_EPIN_NUM_USED 5
+#define UDC_EPOUT_NUM 16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM 9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS 12
+
+#define UDC_EP0OUT_IX 16
+#define UDC_EP0IN_IX 0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR 0x800
+#define UDC_RXFIFO_SIZE 0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR 0xc00
+#define UDC_TXFIFO_SIZE 0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX 1
+#define UDC_EPIN_IX 2
+#define UDC_EPOUT_IX 18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES 4
+#define UDC_BITS_PER_BYTE_SHIFT 3
+#define UDC_BYTE_MASK 0xff
+#define UDC_BITS_PER_BYTE 8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+ /* sca - setup command address */
+ u32 sca;
+
+ /* ep ne's */
+ u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+ /* device configuration */
+ u32 cfg;
+
+ /* device control */
+ u32 ctl;
+
+ /* device status */
+ u32 sts;
+
+ /* device interrupt */
+ u32 irqsts;
+
+ /* device interrupt mask */
+ u32 irqmsk;
+
+ /* endpoint interrupt */
+ u32 ep_irqsts;
+
+ /* endpoint interrupt mask */
+ u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+ /* endpoint control */
+ u32 ctl;
+
+ /* endpoint status */
+ u32 sts;
+
+ /* endpoint buffer size in/ receive packet frame number out */
+ u32 bufin_framenum;
+
+ /* endpoint buffer size out/max packet size */
+ u32 bufout_maxpkt;
+
+ /* endpoint setup buffer pointer */
+ u32 subptr;
+
+ /* endpoint data descriptor pointer */
+ u32 desptr;
+
+ /* reserverd */
+ u32 reserved;
+
+ /* write/read confirmation */
+ u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* first setup word */
+ u32 data12;
+ /* second setup word */
+ u32 data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* buffer pointer */
+ u32 bufptr;
+ /* next descriptor pointer */
+ u32 next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+ /* embedded gadget ep */
+ struct usb_request req;
+
+ /* flags */
+ unsigned dma_going : 1,
+ dma_mapping : 1,
+ dma_done : 1;
+ /* phys. address */
+ dma_addr_t td_phys;
+ /* first dma desc. of chain */
+ struct udc_data_dma *td_data;
+ /* last dma desc. of chain */
+ struct udc_data_dma *td_data_last;
+ struct list_head queue;
+
+ /* chain length */
+ unsigned chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+ struct usb_ep ep;
+ struct udc_ep_regs __iomem *regs;
+ u32 __iomem *txfifo;
+ u32 __iomem *dma;
+ dma_addr_t td_phys;
+ dma_addr_t td_stp_dma;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td;
+ /* temp request */
+ struct udc_request *req;
+ unsigned req_used;
+ unsigned req_completed;
+ /* dummy DMA desc for BNA dummy */
+ struct udc_request *bna_dummy_req;
+ unsigned bna_occurred;
+
+ /* NAK state */
+ unsigned naking;
+
+ struct udc *dev;
+
+ /* queue for requests */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned halted;
+ unsigned cancel_transfer;
+ unsigned num : 5,
+ fifo_depth : 14,
+ in : 1;
+};
+
+/* device struct */
+struct udc {
+ struct usb_gadget gadget;
+ spinlock_t lock; /* protects all state */
+ /* all endpoints */
+ struct udc_ep ep[UDC_EP_NUM];
+ struct usb_gadget_driver *driver;
+ /* operational flags */
+ unsigned active : 1,
+ stall_ep0in : 1,
+ waiting_zlp_ack_ep0in : 1,
+ set_cfg_not_acked : 1,
+ irq_registered : 1,
+ data_ep_enabled : 1,
+ data_ep_queued : 1,
+ mem_region : 1,
+ sys_suspended : 1,
+ connected;
+
+ u16 chiprev;
+
+ /* registers */
+ struct pci_dev *pdev;
+ struct udc_csrs __iomem *csr;
+ struct udc_regs __iomem *regs;
+ struct udc_ep_regs __iomem *ep_regs;
+ u32 __iomem *rxfifo;
+ u32 __iomem *txfifo;
+
+ /* DMA desc pools */
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+
+ /* device data */
+ unsigned long phys_addr;
+ void __iomem *virt_addr;
+ unsigned irq;
+
+ /* states */
+ u16 cur_config;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+ u32 data[2];
+ struct usb_ctrlrequest request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ ((u32Val) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name) \
+ ((u32Val & ((u32) bitfield_stub_name##_MASK)) \
+ >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(udc , args...) do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index dbaf867436d..a3376739a81 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -305,6 +305,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DEV_CONFIG_CDC
+#endif
+
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 53e9139ba38..f7f159c1002 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -17,6 +17,12 @@
#define gadget_is_net2280(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
#else
@@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
- else if (gadget_is_m66592(gadget))
+ else if (gadget_is_amd5536udc(gadget))
return 0x20;
+ else if (gadget_is_m66592(gadget))
+ return 0x21;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 0174a322e00..700dda8a915 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -21,26 +21,18 @@
*/
#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
+
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
#include "m66592-udc.h"
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
@@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda");
/* module parameters */
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)");
+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 = 0;
+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)");
+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)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+ "(default=2)");
static const char udc_name[] = "m66592_udc";
static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t gfp_flags);
static void transfer_complete(struct m66592_ep *ep,
- struct m66592_request *req,
- int status);
+ struct m66592_request *req, int status);
+
/*-------------------------------------------------------------------------*/
static inline u16 get_usb_speed(struct m66592 *m66592)
{
@@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592)
}
static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
- unsigned long reg)
+ unsigned long reg)
{
u16 tmp;
tmp = m66592_read(m66592, M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bset(m66592, (1 << pipenum), reg);
m66592_write(m66592, tmp, M66592_INTENB0);
}
static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
- unsigned long reg)
+ unsigned long reg)
{
u16 tmp;
tmp = m66592_read(m66592, M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bclr(m66592, (1 << pipenum), reg);
m66592_write(m66592, tmp, M66592_INTENB0);
}
@@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592)
{
m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
}
static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
- M66592_INTENB0);
+ M66592_INTENB0);
m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
@@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
}
static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
- u16 pid)
+ u16 pid)
{
unsigned long offset;
@@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
}
static int pipe_buffer_setting(struct m66592 *m66592,
- struct m66592_pipe_info *info)
+ struct m66592_pipe_info *info)
{
u16 bufnum = 0, buf_bsize = 0;
u16 pipecfg = 0;
@@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
}
if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
- m66592->bi_bufnum);
+ m66592->bi_bufnum);
return -ENOMEM;
}
@@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
m66592->bulk--;
} else
printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
- info->pipe);
+ info->pipe);
}
static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep)
}
static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
- const struct usb_endpoint_descriptor *desc,
- u16 pipenum, int dma)
+ const struct usb_endpoint_descriptor *desc,
+ u16 pipenum, int dma)
{
if ((pipenum != 0) && dma) {
if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
ep->pipectr = get_pipectr_addr(pipenum);
ep->pipenum = pipenum;
- ep->ep.maxpacket = desc->wMaxPacketSize;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
m66592->pipenum2ep[pipenum] = ep;
m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep)
}
static int alloc_pipe_config(struct m66592_ep *ep,
- const struct usb_endpoint_descriptor *desc)
+ const struct usb_endpoint_descriptor *desc)
{
struct m66592 *m66592 = ep->m66592;
struct m66592_pipe_info info;
@@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep,
BUG_ON(ep->pipenum);
- switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_BULK:
if (m66592->bulk >= M66592_MAX_NUM_BULK) {
if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
printk(KERN_ERR "bulk pipe is insufficient\n");
return -ENODEV;
} else {
- info.pipe = M66592_BASE_PIPENUM_ISOC +
- m66592->isochronous;
+ info.pipe = M66592_BASE_PIPENUM_ISOC
+ + m66592->isochronous;
counter = &m66592->isochronous;
}
} else {
@@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
ep->type = info.type;
info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = desc->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
info.interval = desc->bInterval;
if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
info.dir_in = 1;
@@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
pipe_change(m66592, ep->pipenum);
m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
- (M66592_ISEL | M66592_CURPIPE),
- M66592_CFIFOSEL);
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
m66592_write(m66592, M66592_BCLR, ep->fifoctr);
if (req->req.length == 0) {
m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
if (ep->pipenum == 0) {
m66592_mdfy(m66592, M66592_PIPE0,
- (M66592_ISEL | M66592_CURPIPE),
- M66592_CFIFOSEL);
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
m66592_write(m66592, M66592_BCLR, ep->fifoctr);
pipe_start(m66592, pipenum);
pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
pipe_change(m66592, pipenum);
m66592_bset(m66592, M66592_TRENB, ep->fifosel);
m66592_write(m66592,
- (req->req.length + ep->ep.maxpacket - 1) /
- ep->ep.maxpacket, ep->fifotrn);
+ (req->req.length + ep->ep.maxpacket - 1)
+ / ep->ep.maxpacket,
+ ep->fifotrn);
}
pipe_start(m66592, pipenum); /* trigger once */
pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
static void init_controller(struct m66592 *m66592)
{
m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
- M66592_PINCFG);
+ M66592_PINCFG);
m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
@@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592)
m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
- M66592_DMA0CFG);
+ M66592_DMA0CFG);
}
static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592)
/*-------------------------------------------------------------------------*/
static void transfer_complete(struct m66592_ep *ep,
- struct m66592_request *req,
- int status)
+ struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
int restart = 0;
@@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep,
if (!list_empty(&ep->queue))
restart = 1;
- if (likely(req->req.complete))
- req->req.complete(&ep->ep, &req->req);
+ spin_unlock(&ep->m66592->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->m66592->lock);
if (restart) {
req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep,
static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
{
int i;
- volatile u16 tmp;
+ u16 tmp;
unsigned bufsize;
size_t size;
void *buf;
@@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
req->req.actual += size;
/* check transfer finish */
- if ((!req->req.zero && (req->req.actual == req->req.length)) ||
- (size % ep->ep.maxpacket) || (size == 0)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
disable_irq_ready(m66592, pipenum);
disable_irq_empty(m66592, pipenum);
} else {
@@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
/* write fifo */
if (req->req.buf) {
m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
- if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
- ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+ if ((size == 0)
+ || ((size % ep->ep.maxpacket) != 0)
+ || ((bufsize != ep->ep.maxpacket)
+ && (bufsize > size)))
m66592_bset(m66592, M66592_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)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
disable_irq_ready(m66592, pipenum);
enable_irq_empty(m66592, pipenum);
} else {
@@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
req->req.actual += size;
/* check transfer finish */
- if ((!req->req.zero && (req->req.actual == req->req.length)) ||
- (size % ep->ep.maxpacket) || (size == 0)) {
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
pipe_stop(m66592, pipenum);
pipe_irq_disable(m66592, pipenum);
finish = 1;
@@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
- M66592_CFIFOSEL);
+ M66592_CFIFOSEL);
ep = &m66592->ep[0];
req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
}
static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
struct m66592_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; /* selfpower */
+ status = 1 << USB_DEVICE_SELF_POWERED;
break;
case USB_RECIP_INTERFACE:
status = 0;
break;
case USB_RECIP_ENDPOINT:
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pid = control_reg_get_pid(m66592, ep->pipenum);
if (pid == M66592_PID_STALL)
- status = 1;
+ status = 1 << USB_ENDPOINT_HALT;
else
status = 0;
break;
@@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
return; /* exit */
}
- *m66592->ep0_buf = status;
- m66592->ep0_req->buf = m66592->ep0_buf;
+ m66592->ep0_data = cpu_to_le16(status);
+ m66592->ep0_req->buf = &m66592->ep0_data;
m66592->ep0_req->length = 2;
/* AV: what happens if we get called again before that gets through? */
+ spin_unlock(&m66592->lock);
m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+ spin_lock(&m66592->lock);
}
static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
case USB_RECIP_ENDPOINT: {
struct m66592_ep *ep;
struct m66592_request *req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pipe_stop(m66592, ep->pipenum);
control_reg_sqclr(m66592, ep->pipenum);
@@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
break;
case USB_RECIP_ENDPOINT: {
struct m66592_ep *ep;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
- ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
pipe_stall(m66592, ep->pipenum);
control_end(m66592, 1);
@@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592)
}
if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
m66592_update_usb_speed(m66592);
- if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
- m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+ && m66592->gadget.speed == USB_SPEED_UNKNOWN)
m66592_update_usb_speed(m66592);
m66592->old_dvsq = dvsq;
}
static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
{
struct usb_ctrlrequest ctrl;
u16 ctsq;
@@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592)
case M66592_CS_WRDS:
case M66592_CS_WRND:
if (setup_packet(m66592, &ctrl)) {
+ spin_unlock(&m66592->lock);
if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
pipe_stall(m66592, 0);
+ spin_lock(&m66592->lock);
}
break;
case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
u16 savepipe;
u16 mask0;
+ spin_lock(&m66592->lock);
+
intsts0 = m66592_read(m66592, M66592_INTSTS0);
intenb0 = m66592_read(m66592, M66592_INTENB0);
@@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
bempenb = m66592_read(m66592, M66592_BEMPENB);
if (mask0 & M66592_VBINT) {
- m66592_write(m66592, (u16)~M66592_VBINT,
- M66592_INTSTS0);
+ m66592_write(m66592, 0xffff & ~M66592_VBINT,
+ M66592_INTSTS0);
m66592_start_xclock(m66592);
/* start vbus sampling */
m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
- & M66592_VBSTS;
+ & M66592_VBSTS;
m66592->scount = M66592_MAX_SAMPLING;
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
if (intsts0 & M66592_DVSQ)
irq_device_state(m66592);
- if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
- (brdysts & brdyenb)) {
+ if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+ && (brdysts & brdyenb)) {
irq_pipe_ready(m66592, brdysts, brdyenb);
}
- if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
- (bempsts & bempenb)) {
+ if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+ && (bempsts & bempenb)) {
irq_pipe_empty(m66592, bempsts, bempenb);
}
@@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
m66592_write(m66592, savepipe, M66592_CFIFOSEL);
+ spin_unlock(&m66592->lock);
return IRQ_HANDLED;
}
@@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592)
m66592_usb_disconnect(m66592);
} else {
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
} else {
m66592->scount = M66592_MAX_SAMPLING;
m66592->old_vbus = tmp;
mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ jiffies + msecs_to_jiffies(50));
}
}
spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1335,11 +1356,6 @@ out:
return ret;
}
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
- return -EOPNOTSUPP;
-}
-
static void m66592_fifo_flush(struct usb_ep *_ep)
{
struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = {
.dequeue = m66592_dequeue,
.set_halt = m66592_set_halt,
- .fifo_status = m66592_fifo_status,
.fifo_flush = m66592_fifo_flush,
};
@@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
struct m66592 *m66592 = the_controller;
int retval;
- if (!driver ||
- driver->speed != USB_SPEED_HIGH ||
- !driver->bind ||
- !driver->unbind ||
- !driver->setup)
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
return -EINVAL;
if (!m66592)
return -ENODEV;
@@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
m66592->old_vbus = m66592_read(m66592,
M66592_INTSTS0) & M66592_VBSTS;
m66592->scount = M66592_MAX_SAMPLING;
- mod_timer(&m66592->timer,
- jiffies + msecs_to_jiffies(50));
+ mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
}
return 0;
@@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
struct m66592 *m66592 = the_controller;
unsigned long flags;
+ if (driver != m66592->driver || !driver->unbind)
+ return -EINVAL;
+
spin_lock_irqsave(&m66592->lock, flags);
if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = {
.get_frame = m66592_get_frame,
};
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
- pdev->dev.power.power_state = state;
- return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
- pdev->dev.power.power_state = PMSG_ON;
- return 0;
-}
-#else /* if defined(CONFIG_PM) */
-#define m66592_suspend NULL
-#define m66592_resume NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
{
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
kfree(m66592);
return 0;
}
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
#define resource_len(r) (((r)->end - (r)->start) + 1)
+
static int __init m66592_probe(struct platform_device *pdev)
{
- struct resource *res = NULL;
- int irq = -1;
+ struct resource *res;
+ int irq;
void __iomem *reg = NULL;
struct m66592 *m66592 = NULL;
int ret = 0;
int i;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- (char *)udc_name);
+ (char *)udc_name);
if (!res) {
ret = -ENODEV;
printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->bi_bufnum = M66592_BASE_BUFNUM;
ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
- udc_name, m66592);
+ udc_name, m66592);
if (ret < 0) {
printk(KERN_ERR "request_irq error (%d)\n", ret);
goto clean_up;
@@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev)
if (i != 0) {
INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
list_add_tail(&m66592->ep[i].ep.ep_list,
- &m66592->gadget.ep_list);
+ &m66592->gadget.ep_list);
}
ep->m66592 = m66592;
INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev)
the_controller = m66592;
- /* AV: leaks */
m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
if (m66592->ep0_req == NULL)
- goto clean_up;
- /* AV: leaks, and do we really need it separately allocated? */
- m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
- if (m66592->ep0_buf == NULL)
- goto clean_up;
+ goto clean_up2;
+ m66592->ep0_req->complete = nop_completion;
init_controller(m66592);
- printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
+clean_up2:
+ free_irq(irq, m66592);
clean_up:
if (m66592) {
if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@ clean_up:
/*-------------------------------------------------------------------------*/
static struct platform_driver m66592_driver = {
- .probe = m66592_probe,
- .remove = m66592_remove,
- .suspend = m66592_suspend,
- .resume = m66592_resume,
+ .remove = __exit_p(m66592_remove),
.driver = {
.name = (char *) udc_name,
},
@@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = {
static int __init m66592_udc_init(void)
{
- return platform_driver_register(&m66592_driver);
+ return platform_driver_probe(&m66592_driver, m66592_probe);
}
module_init(m66592_udc_init);
@@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void)
platform_driver_unregister(&m66592_driver);
}
module_exit(m66592_udc_cleanup);
-
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 26b54f8b894..bfa0c645f22 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -24,73 +24,73 @@
#define __M66592_UDC_H__
#define M66592_SYSCFG 0x00
-#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
-#define M66592_XTAL48 0x8000 /* 48MHz */
-#define M66592_XTAL24 0x4000 /* 24MHz */
-#define M66592_XTAL12 0x0000 /* 12MHz */
-#define M66592_XCKE 0x2000 /* b13: External clock enable */
-#define M66592_RCKE 0x1000 /* b12: Register clock enable */
-#define M66592_PLLC 0x0800 /* b11: PLL control */
-#define M66592_SCKE 0x0400 /* b10: USB clock enable */
-#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */
-#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
-#define M66592_DCFM 0x0040 /* b6: Controller function select */
-#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
-#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
-#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
-#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
-#define M66592_USBE 0x0001 /* b0: USB module operation enable */
+#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
+#define M66592_XTAL48 0x8000 /* 48MHz */
+#define M66592_XTAL24 0x4000 /* 24MHz */
+#define M66592_XTAL12 0x0000 /* 12MHz */
+#define M66592_XCKE 0x2000 /* b13: External clock enable */
+#define M66592_RCKE 0x1000 /* b12: Register clock enable */
+#define M66592_PLLC 0x0800 /* b11: PLL control */
+#define M66592_SCKE 0x0400 /* b10: USB clock enable */
+#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */
+#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
+#define M66592_DCFM 0x0040 /* b6: Controller function select */
+#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
+#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
+#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
+#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
+#define M66592_USBE 0x0001 /* b0: USB module operation enable */
#define M66592_SYSSTS 0x02
-#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
-#define M66592_SE1 0x0003 /* SE1 */
-#define M66592_KSTS 0x0002 /* K State */
-#define M66592_JSTS 0x0001 /* J State */
-#define M66592_SE0 0x0000 /* SE0 */
+#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
+#define M66592_SE1 0x0003 /* SE1 */
+#define M66592_KSTS 0x0002 /* K State */
+#define M66592_JSTS 0x0001 /* J State */
+#define M66592_SE0 0x0000 /* SE0 */
#define M66592_DVSTCTR 0x04
-#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
-#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
-#define M66592_USBRST 0x0040 /* b6: USB reset enable */
-#define M66592_RESUME 0x0020 /* b5: Resume enable */
-#define M66592_UACT 0x0010 /* b4: USB bus enable */
-#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
-#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
-#define M66592_FSMODE 0x0002 /* Full-Speed mode */
-#define M66592_HSPROC 0x0001 /* HS handshake is processing */
+#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
+#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define M66592_USBRST 0x0040 /* b6: USB reset enable */
+#define M66592_RESUME 0x0020 /* b5: Resume enable */
+#define M66592_UACT 0x0010 /* b4: USB bus enable */
+#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
+#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
+#define M66592_FSMODE 0x0002 /* Full-Speed mode */
+#define M66592_HSPROC 0x0001 /* HS handshake is processing */
#define M66592_TESTMODE 0x06
-#define M66592_UTST 0x000F /* b4-0: Test select */
-#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
-#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
-#define M66592_H_TST_K 0x000A /* HOST TEST K */
-#define M66592_H_TST_J 0x0009 /* HOST TEST J */
-#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
-#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
-#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
-#define M66592_P_TST_K 0x0002 /* PERI TEST K */
-#define M66592_P_TST_J 0x0001 /* PERI TEST J */
-#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+#define M66592_UTST 0x000F /* b4-0: Test select */
+#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define M66592_H_TST_K 0x000A /* HOST TEST K */
+#define M66592_H_TST_J 0x0009 /* HOST TEST J */
+#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define M66592_P_TST_K 0x0002 /* PERI TEST K */
+#define M66592_P_TST_J 0x0001 /* PERI TEST J */
+#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
#define M66592_PINCFG 0x0A
-#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
-#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
+#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
+#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
#define M66592_DMA0CFG 0x0C
#define M66592_DMA1CFG 0x0E
-#define M66592_DREQA 0x4000 /* b14: Dreq active select */
-#define M66592_BURST 0x2000 /* b13: Burst mode */
-#define M66592_DACKA 0x0400 /* b10: Dack active select */
-#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
-#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
-#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
-#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
-#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
-#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
-#define M66592_DENDA 0x0040 /* b6: Dend active select */
-#define M66592_PKTM 0x0020 /* b5: Packet mode */
-#define M66592_DENDE 0x0010 /* b4: Dend enable */
-#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
+#define M66592_DREQA 0x4000 /* b14: Dreq active select */
+#define M66592_BURST 0x2000 /* b13: Burst mode */
+#define M66592_DACKA 0x0400 /* b10: Dack active select */
+#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
+#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA 0x0040 /* b6: Dend active select */
+#define M66592_PKTM 0x0020 /* b5: Packet mode */
+#define M66592_DENDE 0x0010 /* b4: Dend enable */
+#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
@@ -99,300 +99,300 @@
#define M66592_CFIFOSEL 0x1E
#define M66592_D0FIFOSEL 0x24
#define M66592_D1FIFOSEL 0x2A
-#define M66592_RCNT 0x8000 /* b15: Read count mode */
-#define M66592_REW 0x4000 /* b14: Buffer rewind */
-#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
-#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
-#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */
-#define M66592_MBW_8 0x0000 /* 8bit */
-#define M66592_MBW_16 0x0400 /* 16bit */
-#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
-#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
-#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */
-#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
-#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
+#define M66592_RCNT 0x8000 /* b15: Read count mode */
+#define M66592_REW 0x4000 /* b14: Buffer rewind */
+#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
+#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#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 */
+#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
#define M66592_CFIFOCTR 0x20
#define M66592_D0FIFOCTR 0x26
#define M66592_D1FIFOCTR 0x2c
-#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
-#define M66592_BCLR 0x4000 /* b14: Buffer clear */
-#define M66592_FRDY 0x2000 /* b13: FIFO ready */
-#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
+#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
+#define M66592_BCLR 0x4000 /* b14: Buffer clear */
+#define M66592_FRDY 0x2000 /* b13: FIFO ready */
+#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
#define M66592_CFIFOSIE 0x22
-#define M66592_TGL 0x8000 /* b15: Buffer toggle */
-#define M66592_SCLR 0x4000 /* b14: Buffer clear */
-#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
+#define M66592_TGL 0x8000 /* b15: Buffer toggle */
+#define M66592_SCLR 0x4000 /* b14: Buffer clear */
+#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
#define M66592_D0FIFOTRN 0x28
#define M66592_D1FIFOTRN 0x2E
-#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
+#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
#define M66592_INTENB0 0x30
-#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
-#define M66592_RSME 0x4000 /* b14: Resume interrupt */
-#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
-#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
-#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
-#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
-#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
-#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
-#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
-#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
-#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
-#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
-#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */
-#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */
-#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
-#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
+#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
+#define M66592_RSME 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
+#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
+#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
+#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
+#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
+#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
+#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */
+#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */
+#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
+#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
#define M66592_INTENB1 0x32
-#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
-#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
-#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
-#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
-#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
-#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
-#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
+#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
+#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
+#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
#define M66592_BRDYENB 0x36
#define M66592_BRDYSTS 0x46
-#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
-#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
-#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
-#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
-#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
-#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
-#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
-#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
+#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
#define M66592_NRDYENB 0x38
#define M66592_NRDYSTS 0x48
-#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
-#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
-#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
-#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
-#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
-#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
-#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
-#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
+#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
#define M66592_BEMPENB 0x3A
#define M66592_BEMPSTS 0x4A
-#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
-#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
-#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
-#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
-#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
-#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
-#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
-#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
+#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
+#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
+#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
+#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
+#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
+#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
+#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
+#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
#define M66592_SOFCFG 0x3C
-#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
-#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
-#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
-#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
+#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
+#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
+#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
#define M66592_INTSTS0 0x40
-#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
-#define M66592_RESM 0x4000 /* b14: Resume interrupt */
-#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
-#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */
-#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
-#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
-#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
-#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
-#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
-#define M66592_DVSQ 0x0070 /* b6-4: Device state */
-#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
-#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
-#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
-#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
-#define M66592_DS_SUSP 0x0040 /* Suspend */
-#define M66592_DS_CNFG 0x0030 /* Configured */
-#define M66592_DS_ADDS 0x0020 /* Address */
-#define M66592_DS_DFLT 0x0010 /* Default */
-#define M66592_DS_POWR 0x0000 /* Powered */
-#define M66592_DVSQS 0x0030 /* b5-4: Device state */
-#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
-#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
-#define M66592_CS_SQER 0x0006 /* Sequence error */
-#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */
-#define M66592_CS_WRSS 0x0004 /* Control write status stage */
-#define M66592_CS_WRDS 0x0003 /* Control write data stage */
-#define M66592_CS_RDSS 0x0002 /* Control read status stage */
-#define M66592_CS_RDDS 0x0001 /* Control read data stage */
-#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
+#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
+#define M66592_RESM 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define M66592_DVST 0x1000 /* b12: Device state transition */
+#define M66592_CTRT 0x0800 /* b11: Control stage transition */
+#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
+#define M66592_DVSQ 0x0070 /* b6-4: Device state */
+#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define M66592_DS_SUSP 0x0040 /* Suspend */
+#define M66592_DS_CNFG 0x0030 /* Configured */
+#define M66592_DS_ADDS 0x0020 /* Address */
+#define M66592_DS_DFLT 0x0010 /* Default */
+#define M66592_DS_POWR 0x0000 /* Powered */
+#define M66592_DVSQS 0x0030 /* b5-4: Device state */
+#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
+#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define M66592_CS_SQER 0x0006 /* Sequence error */
+#define M66592_CS_WRND 0x0005 /* Control write nodata status */
+#define M66592_CS_WRSS 0x0004 /* Control write status stage */
+#define M66592_CS_WRDS 0x0003 /* Control write data stage */
+#define M66592_CS_RDSS 0x0002 /* Control read status stage */
+#define M66592_CS_RDDS 0x0001 /* Control read data stage */
+#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
#define M66592_INTSTS1 0x42
-#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
-#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
-#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
-#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
#define M66592_FRMNUM 0x4C
-#define M66592_OVRN 0x8000 /* b15: Overrun error */
-#define M66592_CRCE 0x4000 /* b14: Received data error */
-#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
-#define M66592_FRNM 0x07FF /* b10-0: Frame number */
+#define M66592_OVRN 0x8000 /* b15: Overrun error */
+#define M66592_CRCE 0x4000 /* b14: Received data error */
+#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
+#define M66592_FRNM 0x07FF /* b10-0: Frame number */
#define M66592_UFRMNUM 0x4E
-#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
+#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
#define M66592_RECOVER 0x50
-#define M66592_STSRECOV 0x0700 /* Status recovery */
-#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
-#define M66592_STSR_DEFAULT 0x0100 /* Default state */
-#define M66592_STSR_ADDRESS 0x0200 /* Address state */
-#define M66592_STSR_CONFIG 0x0300 /* Configured state */
-#define M66592_USBADDR 0x007F /* b6-0: USB address */
+#define M66592_STSRECOV 0x0700 /* Status recovery */
+#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
+#define M66592_STSR_DEFAULT 0x0100 /* Default state */
+#define M66592_STSR_ADDRESS 0x0200 /* Address state */
+#define M66592_STSR_CONFIG 0x0300 /* Configured state */
+#define M66592_USBADDR 0x007F /* b6-0: USB address */
#define M66592_USBREQ 0x54
-#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
-#define M66592_GET_STATUS 0x0000
-#define M66592_CLEAR_FEATURE 0x0100
-#define M66592_ReqRESERVED 0x0200
-#define M66592_SET_FEATURE 0x0300
-#define M66592_ReqRESERVED1 0x0400
-#define M66592_SET_ADDRESS 0x0500
-#define M66592_GET_DESCRIPTOR 0x0600
-#define M66592_SET_DESCRIPTOR 0x0700
-#define M66592_GET_CONFIGURATION 0x0800
-#define M66592_SET_CONFIGURATION 0x0900
-#define M66592_GET_INTERFACE 0x0A00
-#define M66592_SET_INTERFACE 0x0B00
-#define M66592_SYNCH_FRAME 0x0C00
-#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
-#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */
-#define M66592_HOST_TO_DEVICE 0x0000
-#define M66592_DEVICE_TO_HOST 0x0080
-#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
-#define M66592_STANDARD 0x0000
-#define M66592_CLASS 0x0020
-#define M66592_VENDOR 0x0040
-#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
-#define M66592_DEVICE 0x0000
-#define M66592_INTERFACE 0x0001
-#define M66592_ENDPOINT 0x0002
+#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
+#define M66592_GET_STATUS 0x0000
+#define M66592_CLEAR_FEATURE 0x0100
+#define M66592_ReqRESERVED 0x0200
+#define M66592_SET_FEATURE 0x0300
+#define M66592_ReqRESERVED1 0x0400
+#define M66592_SET_ADDRESS 0x0500
+#define M66592_GET_DESCRIPTOR 0x0600
+#define M66592_SET_DESCRIPTOR 0x0700
+#define M66592_GET_CONFIGURATION 0x0800
+#define M66592_SET_CONFIGURATION 0x0900
+#define M66592_GET_INTERFACE 0x0A00
+#define M66592_SET_INTERFACE 0x0B00
+#define M66592_SYNCH_FRAME 0x0C00
+#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */
+#define M66592_HOST_TO_DEVICE 0x0000
+#define M66592_DEVICE_TO_HOST 0x0080
+#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
+#define M66592_STANDARD 0x0000
+#define M66592_CLASS 0x0020
+#define M66592_VENDOR 0x0040
+#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
+#define M66592_DEVICE 0x0000
+#define M66592_INTERFACE 0x0001
+#define M66592_ENDPOINT 0x0002
#define M66592_USBVAL 0x56
-#define M66592_wValue 0xFFFF /* b15-0: wValue */
+#define M66592_wValue 0xFFFF /* b15-0: wValue */
/* Standard Feature Selector */
-#define M66592_ENDPOINT_HALT 0x0000
-#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
-#define M66592_TEST_MODE 0x0002
+#define M66592_ENDPOINT_HALT 0x0000
+#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
+#define M66592_TEST_MODE 0x0002
/* Descriptor Types */
-#define M66592_DT_TYPE 0xFF00
-#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
-#define M66592_DT_DEVICE 0x01
-#define M66592_DT_CONFIGURATION 0x02
-#define M66592_DT_STRING 0x03
-#define M66592_DT_INTERFACE 0x04
-#define M66592_DT_ENDPOINT 0x05
-#define M66592_DT_DEVICE_QUALIFIER 0x06
-#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
-#define M66592_DT_INTERFACE_POWER 0x08
-#define M66592_DT_INDEX 0x00FF
-#define M66592_CONF_NUM 0x00FF
-#define M66592_ALT_SET 0x00FF
+#define M66592_DT_TYPE 0xFF00
+#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
+#define M66592_DT_DEVICE 0x01
+#define M66592_DT_CONFIGURATION 0x02
+#define M66592_DT_STRING 0x03
+#define M66592_DT_INTERFACE 0x04
+#define M66592_DT_ENDPOINT 0x05
+#define M66592_DT_DEVICE_QUALIFIER 0x06
+#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
+#define M66592_DT_INTERFACE_POWER 0x08
+#define M66592_DT_INDEX 0x00FF
+#define M66592_CONF_NUM 0x00FF
+#define M66592_ALT_SET 0x00FF
#define M66592_USBINDEX 0x58
-#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
-#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */
-#define M66592_TEST_J 0x0100 /* Test_J */
-#define M66592_TEST_K 0x0200 /* Test_K */
-#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
-#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
-#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
-#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
-#define M66592_TEST_Reserved 0x4000 /* Reserved */
-#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */
-#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
-#define M66592_EP_DIR_IN 0x0080
-#define M66592_EP_DIR_OUT 0x0000
+#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
+#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */
+#define M66592_TEST_J 0x0100 /* Test_J */
+#define M66592_TEST_K 0x0200 /* Test_K */
+#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
+#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
+#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
+#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
+#define M66592_TEST_Reserved 0x4000 /* Reserved */
+#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */
+#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
+#define M66592_EP_DIR_IN 0x0080
+#define M66592_EP_DIR_OUT 0x0000
#define M66592_USBLENG 0x5A
-#define M66592_wLength 0xFFFF /* b15-0: wLength */
+#define M66592_wLength 0xFFFF /* b15-0: wLength */
#define M66592_DCPCFG 0x5C
-#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
#define M66592_DCPMAXP 0x5E
-#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
-#define M66592_DEVICE_0 0x0000 /* Device address 0 */
-#define M66592_DEVICE_1 0x4000 /* Device address 1 */
-#define M66592_DEVICE_2 0x8000 /* Device address 2 */
-#define M66592_DEVICE_3 0xC000 /* Device address 3 */
-#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
+#define M66592_DEVICE_0 0x0000 /* Device address 0 */
+#define M66592_DEVICE_1 0x4000 /* Device address 1 */
+#define M66592_DEVICE_2 0x8000 /* Device address 2 */
+#define M66592_DEVICE_3 0xC000 /* Device address 3 */
+#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */
#define M66592_DCPCTR 0x60
-#define M66592_BSTS 0x8000 /* b15: Buffer status */
-#define M66592_SUREQ 0x4000 /* b14: Send USB request */
-#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */
-#define M66592_PID 0x0003 /* b1-0: Response PID */
-#define M66592_PID_STALL 0x0002 /* STALL */
-#define M66592_PID_BUF 0x0001 /* BUF */
-#define M66592_PID_NAK 0x0000 /* NAK */
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_SUREQ 0x4000 /* b14: Send USB request */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL 0x0004 /* b2: control transfer complete */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_PID_STALL 0x0002 /* STALL */
+#define M66592_PID_BUF 0x0001 /* BUF */
+#define M66592_PID_NAK 0x0000 /* NAK */
#define M66592_PIPESEL 0x64
-#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
-#define M66592_PIPE0 0x0000 /* PIPE 0 */
-#define M66592_PIPE1 0x0001 /* PIPE 1 */
-#define M66592_PIPE2 0x0002 /* PIPE 2 */
-#define M66592_PIPE3 0x0003 /* PIPE 3 */
-#define M66592_PIPE4 0x0004 /* PIPE 4 */
-#define M66592_PIPE5 0x0005 /* PIPE 5 */
-#define M66592_PIPE6 0x0006 /* PIPE 6 */
-#define M66592_PIPE7 0x0007 /* PIPE 7 */
+#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
+#define M66592_PIPE0 0x0000 /* PIPE 0 */
+#define M66592_PIPE1 0x0001 /* PIPE 1 */
+#define M66592_PIPE2 0x0002 /* PIPE 2 */
+#define M66592_PIPE3 0x0003 /* PIPE 3 */
+#define M66592_PIPE4 0x0004 /* PIPE 4 */
+#define M66592_PIPE5 0x0005 /* PIPE 5 */
+#define M66592_PIPE6 0x0006 /* PIPE 6 */
+#define M66592_PIPE7 0x0007 /* PIPE 7 */
#define M66592_PIPECFG 0x66
-#define M66592_TYP 0xC000 /* b15-14: Transfer type */
-#define M66592_ISO 0xC000 /* Isochronous */
-#define M66592_INT 0x8000 /* Interrupt */
-#define M66592_BULK 0x4000 /* Bulk */
-#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
-#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
-#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
-#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
-#define M66592_DIR 0x0010 /* b4: Transfer direction select */
-#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
-#define M66592_DIR_P_IN 0x0010 /* PERI IN */
-#define M66592_DIR_H_IN 0x0000 /* HOST IN */
-#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
-#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
-#define M66592_EP1 0x0001
-#define M66592_EP2 0x0002
-#define M66592_EP3 0x0003
-#define M66592_EP4 0x0004
-#define M66592_EP5 0x0005
-#define M66592_EP6 0x0006
-#define M66592_EP7 0x0007
-#define M66592_EP8 0x0008
-#define M66592_EP9 0x0009
-#define M66592_EP10 0x000A
-#define M66592_EP11 0x000B
-#define M66592_EP12 0x000C
-#define M66592_EP13 0x000D
-#define M66592_EP14 0x000E
-#define M66592_EP15 0x000F
+#define M66592_TYP 0xC000 /* b15-14: Transfer type */
+#define M66592_ISO 0xC000 /* Isochronous */
+#define M66592_INT 0x8000 /* Interrupt */
+#define M66592_BULK 0x4000 /* Bulk */
+#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define M66592_DIR 0x0010 /* b4: Transfer direction select */
+#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
+#define M66592_DIR_P_IN 0x0010 /* PERI IN */
+#define M66592_DIR_H_IN 0x0000 /* HOST IN */
+#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
+#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
+#define M66592_EP1 0x0001
+#define M66592_EP2 0x0002
+#define M66592_EP3 0x0003
+#define M66592_EP4 0x0004
+#define M66592_EP5 0x0005
+#define M66592_EP6 0x0006
+#define M66592_EP7 0x0007
+#define M66592_EP8 0x0008
+#define M66592_EP9 0x0009
+#define M66592_EP10 0x000A
+#define M66592_EP11 0x000B
+#define M66592_EP12 0x000C
+#define M66592_EP13 0x000D
+#define M66592_EP14 0x000E
+#define M66592_EP15 0x000F
#define M66592_PIPEBUF 0x68
-#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
-#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
-#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
#define M66592_PIPEMAXP 0x6A
-#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
+#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
#define M66592_PIPEPERI 0x6C
-#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
-#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */
+#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */
+#define M66592_IITV 0x0007 /* b2-0: ISO interval */
#define M66592_PIPE1CTR 0x70
#define M66592_PIPE2CTR 0x72
@@ -401,19 +401,17 @@
#define M66592_PIPE5CTR 0x78
#define M66592_PIPE6CTR 0x7A
#define M66592_PIPE7CTR 0x7C
-#define M66592_BSTS 0x8000 /* b15: Buffer status */
-#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
-#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
-#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
-#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
-#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
#define M66592_INVALID_REG 0x7E
-#define __iomem
-
#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2)
#define M66592_MAX_SAMPLING 10
@@ -449,7 +447,7 @@ struct m66592_ep {
struct m66592 *m66592;
struct list_head queue;
- unsigned busy:1;
+ unsigned busy:1;
unsigned internal_ccpl:1; /* use only control */
/* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@ struct m66592 {
struct m66592_ep *epaddr2ep[16];
struct usb_request *ep0_req; /* for internal request */
- u16 *ep0_buf; /* for internal request */
+ u16 ep0_data; /* for internal request */
struct timer_list timer;
@@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
}
static inline void m66592_read_fifo(struct m66592 *m66592,
- unsigned long offset,
- void *buf, unsigned long len)
+ unsigned long offset,
+ void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
@@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
}
static inline void m66592_write_fifo(struct m66592 *m66592,
- unsigned long offset,
- void *buf, unsigned long len)
+ unsigned long offset,
+ void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
- unsigned long offset)
+ unsigned long offset)
{
u16 tmp;
tmp = m66592_read(m66592, offset);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 38138bb9ddb..9cd98e73dc1 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/mutex.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -258,7 +259,7 @@ static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_NOTIFY_NAME;
-static struct semaphore gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@ static int __init gs_module_init(void)
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i=0; i < GS_NUM_PORTS; i++)
- sema_init(&gs_open_close_sem[i], 1);
+ mutex_init(&gs_open_close_lock[i]);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
@@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
struct gs_port *port;
struct gs_dev *dev;
struct gs_buf *buf;
- struct semaphore *sem;
+ struct mutex *mtx;
int ret;
port_num = tty->index;
@@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
return -ENODEV;
}
- sem = &gs_open_close_sem[port_num];
- if (down_interruptible(sem)) {
+ mtx = &gs_open_close_lock[port_num];
+ if (mutex_lock_interruptible(mtx)) {
printk(KERN_ERR
- "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+ "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
port_num, tty, file);
return -ERESTARTSYS;
}
@@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
exit_unlock_port:
spin_unlock_irqrestore(&port->port_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
exit_unlock_dev:
spin_unlock_irqrestore(&dev->dev_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
}
@@ -781,7 +782,7 @@ exit_unlock_dev:
static void gs_close(struct tty_struct *tty, struct file *file)
{
struct gs_port *port = tty->driver_data;
- struct semaphore *sem;
+ struct mutex *mtx;
if (port == NULL) {
printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
- sem = &gs_open_close_sem[port->port_num];
- down(sem);
+ mtx = &gs_open_close_lock[port->port_num];
+ mutex_lock(mtx);
spin_lock_irq(&port->port_lock);
@@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
exit:
spin_unlock_irq(&port->port_lock);
- up(sem);
+ mutex_unlock(mtx);
}
/*
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46873f2534b..5c851a36de7 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
struct urb, urb_list);
ptd = &ep->ptd;
len = ep->length;
- spin_lock(&urb->lock);
ep->data = (unsigned char *)urb->transfer_buffer
+ urb->actual_length;
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
| PTD_EP(ep->epnum);
ptd->len = PTD_LEN(len) | PTD_DIR(dir);
ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
- spin_unlock(&urb->lock);
if (!ep->active) {
ptd->mps |= PTD_LAST_MSK;
isp116x->atl_last_dir = dir;
@@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
}
/*
+ Take done or failed requests out of schedule. Give back
+ processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+ struct urb *urb)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+ unsigned i;
+
+ urb->hcpriv = NULL;
+ ep->error_count = 0;
+
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_SETUP;
+
+ urb_dbg(urb, "Finish");
+
+ spin_unlock(&isp116x->lock);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+ spin_lock(&isp116x->lock);
+
+ /* take idle endpoints out of the schedule */
+ if (!list_empty(&ep->hep->urb_list))
+ return;
+
+ /* async deschedule */
+ if (!list_empty(&ep->schedule)) {
+ list_del_init(&ep->schedule);
+ return;
+ }
+
+ /* periodic deschedule */
+ DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+ struct isp116x_ep *temp;
+ struct isp116x_ep **prev = &isp116x->periodic[i];
+
+ while (*prev && ((temp = *prev) != ep))
+ prev = &temp->next;
+ if (*prev)
+ *prev = ep->next;
+ isp116x->load[i] -= ep->load;
+ }
+ ep->branch = PERIODIC_SIZE;
+ isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+ ep->load / ep->period;
+
+ /* switch irq type? */
+ if (!--isp116x->periodic_count) {
+ isp116x->irqenb &= ~HCuPINT_SOF;
+ isp116x->irqenb |= HCuPINT_ATL;
+ }
+}
+
+/*
Analyze transfer results, handle partial transfers and errors
*/
static void postproc_atl_queue(struct isp116x *isp116x)
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
struct usb_device *udev;
struct ptd *ptd;
int short_not_ok;
+ int status;
u8 cc;
for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
ptd = &ep->ptd;
cc = PTD_GET_CC(ptd);
short_not_ok = 1;
- spin_lock(&urb->lock);
+ status = -EINPROGRESS;
/* Data underrun is special. For allowed underrun
we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x)
immediately while for control transfer,
we do a STATUS stage. */
if (cc == TD_DATAUNDERRUN) {
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
- DBG("Allowed data underrun\n");
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+ usb_pipecontrol(urb->pipe)) {
+ DBG("Allowed or control data underrun\n");
cc = TD_CC_NOERROR;
short_not_ok = 0;
} else {
ep->error_count = 1;
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_ACK;
- else
- usb_settoggle(udev, ep->epnum,
- ep->nextpid ==
- USB_PID_OUT,
- PTD_GET_TOGGLE(ptd));
+ usb_settoggle(udev, ep->epnum,
+ ep->nextpid == USB_PID_OUT,
+ PTD_GET_TOGGLE(ptd));
urb->actual_length += PTD_GET_COUNT(ptd);
- urb->status = cc_to_error[TD_DATAUNDERRUN];
- spin_unlock(&urb->lock);
- continue;
+ status = cc_to_error[TD_DATAUNDERRUN];
+ goto done;
}
}
- /* Keep underrun error through the STATUS stage */
- if (urb->status == cc_to_error[TD_DATAUNDERRUN])
- cc = TD_DATAUNDERRUN;
if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
&& (++ep->error_count >= 3 || cc == TD_CC_STALL
|| cc == TD_DATAOVERRUN)) {
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error[cc];
+ status = cc_to_error[cc];
if (ep->nextpid == USB_PID_ACK)
ep->nextpid = 0;
- spin_unlock(&urb->lock);
- continue;
+ goto done;
}
/* According to usb spec, zero-length Int transfer signals
finishing of the urb. Hey, does this apply only
for IN endpoints? */
if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
- spin_unlock(&urb->lock);
- continue;
+ status = 0;
+ goto done;
}
/* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
/* All data for this URB is transferred, let's finish */
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
- else if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ else
+ status = 0;
break;
case USB_PID_SETUP:
if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length <
+ urb->transfer_buffer_length)
+ status = -EREMOTEIO;
+ else
+ status = 0;
ep->nextpid = 0;
break;
default:
BUG();
}
- spin_unlock(&urb->lock);
- }
-}
-
-/*
- Take done or failed requests out of schedule. Give back
- processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
- unsigned i;
-
- urb->hcpriv = NULL;
- ep->error_count = 0;
-
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_SETUP;
-
- urb_dbg(urb, "Finish");
-
- spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
- spin_lock(&isp116x->lock);
-
- /* take idle endpoints out of the schedule */
- if (!list_empty(&ep->hep->urb_list))
- return;
-
- /* async deschedule */
- if (!list_empty(&ep->schedule)) {
- list_del_init(&ep->schedule);
- return;
- }
- /* periodic deschedule */
- DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
- for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
- struct isp116x_ep *temp;
- struct isp116x_ep **prev = &isp116x->periodic[i];
-
- while (*prev && ((temp = *prev) != ep))
- prev = &temp->next;
- if (*prev)
- *prev = ep->next;
- isp116x->load[i] -= ep->load;
- }
- ep->branch = PERIODIC_SIZE;
- isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
- ep->load / ep->period;
-
- /* switch irq type? */
- if (!--isp116x->periodic_count) {
- isp116x->irqenb &= ~HCuPINT_SOF;
- isp116x->irqenb |= HCuPINT_ATL;
+ done:
+ if (status != -EINPROGRESS) {
+ spin_lock(&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock(&urb->lock);
+ }
+ if (urb->status != -EINPROGRESS)
+ finish_request(isp116x, ep, urb);
}
}
@@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
*/
static void finish_atl_transfers(struct isp116x *isp116x)
{
- struct isp116x_ep *ep;
- struct urb *urb;
-
if (!isp116x->atl_active)
return;
/* Fifo not ready? */
@@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
atomic_inc(&isp116x->atl_finishing);
unpack_fifo(isp116x);
postproc_atl_queue(isp116x);
- for (ep = isp116x->atl_active; ep; ep = ep->active) {
- urb =
- container_of(ep->hep->urb_list.next, struct urb, urb_list);
- /* USB_PID_ACK check here avoids finishing of
- control transfers, for which TD_DATAUNDERRUN
- occured, while URB_SHORT_NOT_OK was set */
- if (urb && urb->status != -EINPROGRESS
- && ep->nextpid != USB_PID_ACK)
- finish_request(isp116x, ep, urb);
- }
atomic_dec(&isp116x->atl_finishing);
}
@@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
/* in case of unlink-during-submit */
- spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
finish_request(isp116x, ep, urb);
ret = 0;
goto fail;
}
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
start_atl_transfers(isp116x);
fail:
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a7a7070c6e2..d60f1985320 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -35,10 +35,8 @@
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
#include "../core/hcd.h"
#include "r8a66597.h"
@@ -54,16 +52,21 @@ static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */
static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=0)");
+
static unsigned short vif = LDRV;
module_param(vif, ushort, 0644);
MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
static unsigned short irq_sense = INTL;
module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+ "(default=32)");
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
struct r8a66597_device *dev;
int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */
- dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
if (dev == NULL)
return -ENOMEM;
@@ -611,33 +614,33 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
memset(array, 0, sizeof(array));
- switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
- case USB_ENDPOINT_XFER_BULK:
+ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
array[i++] = 4;
else {
array[i++] = 3;
array[i++] = 5;
}
- break;
- case USB_ENDPOINT_XFER_INT:
+ break;
+ case USB_ENDPOINT_XFER_INT:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
array[i++] = 6;
array[i++] = 7;
array[i++] = 8;
} else
array[i++] = 9;
- break;
- case USB_ENDPOINT_XFER_ISOC:
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
array[i++] = 2;
else
array[i++] = 1;
- break;
- default:
- err("Illegal type");
- return 0;
- }
+ break;
+ default:
+ err("Illegal type");
+ return 0;
+ }
i = 1;
min = array[0];
@@ -654,7 +657,7 @@ static u16 get_r8a66597_type(__u8 type)
{
u16 r8a66597_type;
- switch(type) {
+ switch (type) {
case USB_ENDPOINT_XFER_BULK:
r8a66597_type = R8A66597_BULK;
break;
@@ -874,7 +877,7 @@ static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
{
r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
| (1 << USB_PORT_FEAT_C_CONNECTION);
- r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+ r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
}
@@ -917,7 +920,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
DCPMAXP);
- r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+ r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
r8a66597_write(r8a66597, p[i], setup_addr);
@@ -948,19 +951,18 @@ static void prepare_packet_read(struct r8a66597 *r8a66597,
pipe_irq_disable(r8a66597, td->pipenum);
pipe_setting(r8a66597, td);
pipe_stop(r8a66597, td->pipe);
- r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
- BRDYSTS);
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
if (td->pipe->pipetre) {
r8a66597_write(r8a66597, TRCLR,
- td->pipe->pipetre);
+ td->pipe->pipetre);
r8a66597_write(r8a66597,
- (urb->transfer_buffer_length
- + td->maxpacket - 1)
- / td->maxpacket,
- td->pipe->pipetrn);
+ (urb->transfer_buffer_length
+ + td->maxpacket - 1)
+ / td->maxpacket,
+ td->pipe->pipetrn);
r8a66597_bset(r8a66597, TRENB,
- td->pipe->pipetre);
+ td->pipe->pipetre);
}
pipe_start(r8a66597, td->pipe);
@@ -991,7 +993,7 @@ static void prepare_packet_write(struct r8a66597 *r8a66597,
if (td->pipe->pipetre)
r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
}
- r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,21 +1011,21 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
struct urb *urb = td->urb;
r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+ pipe_stop(r8a66597, td->pipe);
if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
- r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ r8a66597_write(r8a66597, BVAL, CFIFOCTR);
enable_irq_empty(r8a66597, 0);
} else {
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
r8a66597_write(r8a66597, BCLR, CFIFOCTR);
- r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
- r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
enable_irq_ready(r8a66597, 0);
}
enable_irq_nrdy(r8a66597, 0);
@@ -1269,7 +1271,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
/* write fifo */
if (pipenum > 0)
- r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+ r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
if (urb->transfer_buffer) {
r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1362,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
mask = r8a66597_read(r8a66597, BRDYSTS)
& r8a66597_read(r8a66597, BRDYENB);
- r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+ r8a66597_write(r8a66597, ~mask, BRDYSTS);
if (mask & BRDY0) {
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type == USB_PID_IN)
@@ -1397,7 +1399,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
mask = r8a66597_read(r8a66597, BEMPSTS)
& r8a66597_read(r8a66597, BEMPENB);
- r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+ r8a66597_write(r8a66597, ~mask, BEMPSTS);
if (mask & BEMP0) {
cfifo_change(r8a66597, 0);
td = r8a66597_get_td(r8a66597, 0);
@@ -1434,7 +1436,7 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
- r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+ r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
set_urb_error(r8a66597, 0);
@@ -1488,14 +1490,14 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
if (mask2) {
if (mask2 & ATTCH) {
- r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
/* start usb bus sampling */
start_root_hub_sampling(r8a66597, 1);
}
if (mask2 & DTCH) {
- r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS2);
r8a66597_bclr(r8a66597, DTCHE, INTENB2);
r8a66597_usb_disconnect(r8a66597, 1);
}
@@ -1503,24 +1505,24 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
if (mask1) {
if (mask1 & ATTCH) {
- r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
/* start usb bus sampling */
start_root_hub_sampling(r8a66597, 0);
}
if (mask1 & DTCH) {
- r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS1);
r8a66597_bclr(r8a66597, DTCHE, INTENB1);
r8a66597_usb_disconnect(r8a66597, 0);
}
if (mask1 & SIGN) {
- r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
+ r8a66597_write(r8a66597, ~SIGN, INTSTS1);
set_urb_error(r8a66597, 0);
check_next_phase(r8a66597);
}
if (mask1 & SACK) {
- r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
+ r8a66597_write(r8a66597, ~SACK, INTSTS1);
check_next_phase(r8a66597);
}
}
@@ -1663,13 +1665,9 @@ static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
static int r8a66597_start(struct usb_hcd *hcd)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
- int ret;
hcd->state = HC_STATE_RUNNING;
- if ((ret = enable_controller(r8a66597)) < 0)
- return ret;
-
- return 0;
+ return enable_controller(r8a66597);
}
static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1694,12 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
struct urb *urb,
- struct usb_host_endpoint *hep,
- gfp_t mem_flags)
+ struct usb_host_endpoint *hep)
{
struct r8a66597_td *td;
u16 pipenum;
- td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+ td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
if (td == NULL)
return NULL;
@@ -1741,7 +1738,8 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
}
if (!hep->hcpriv) {
- hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+ hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+ GFP_ATOMIC);
if (!hep->hcpriv) {
ret = -ENOMEM;
goto error;
@@ -1755,7 +1753,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
init_pipe_config(r8a66597, urb);
set_address_zero(r8a66597, urb);
- td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+ td = r8a66597_make_td(r8a66597, urb, hep);
if (td == NULL) {
ret = -ENOMEM;
goto error;
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 97c2a71ac7a..fe9ceb077d9 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -203,14 +203,14 @@
#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 */
+#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 */
@@ -268,16 +268,16 @@
#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 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 */
@@ -315,13 +315,10 @@
/* Micro Frame Number Register */
#define UFRNM 0x0007 /* b2-0: Micro frame number */
-/* USB Address / Low Power Status Recovery Register */
-//#define USBADDR 0x007F /* b6-0: USB address */
-
/* 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 */
+#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 */
@@ -366,21 +363,21 @@
#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 */
+#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 */
+#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 */
@@ -407,15 +404,15 @@
#define make_devsel(addr) (addr << 12)
struct r8a66597_pipe_info {
- u16 pipenum;
- u16 address; /* R8A66597 HCD usb addres */
- u16 epnum;
- u16 maxpacket;
- u16 type;
- u16 bufnum;
- u16 buf_bsize;
- u16 interval;
- u16 dir_in;
+ u16 pipenum;
+ u16 address; /* R8A66597 HCD usb addres */
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 bufnum;
+ u16 buf_bsize;
+ u16 interval;
+ u16 dir_in;
};
struct r8a66597_pipe {
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index e98df2ee990..7f765ec038c 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -52,6 +52,7 @@
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/pci_ids.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -83,7 +84,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
* u132_module_lock exists to protect access to global variables
*
*/
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
static int u132_exiting = 0;
static int u132_instances = 0;
static struct list_head u132_static_list;
@@ -258,10 +259,10 @@ static void u132_hcd_delete(struct kref *kref)
struct platform_device *pdev = u132->platform_dev;
struct usb_hcd *hcd = u132_to_hcd(u132);
u132->going += 1;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_del_init(&u132->u132_list);
u132_instances -= 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
"2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
usb_put_hcd(hcd);
@@ -3111,10 +3112,10 @@ static int __devinit u132_probe(struct platform_device *pdev)
int retval = 0;
struct u132 *u132 = hcd_to_u132(hcd);
hcd->rsrc_start = 0;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_add_tail(&u132->u132_list, &u132_static_list);
u132->sequence_num = ++u132_instances;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
u132_u132_init_kref(u132);
u132_initialise(u132, pdev);
hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3217,7 @@ static int __init u132_hcd_init(void)
INIT_LIST_HEAD(&u132_static_list);
u132_instances = 0;
u132_exiting = 0;
- init_MUTEX(&u132_module_lock);
+ mutex_init(&u132_module_lock);
if (usb_disabled())
return -ENODEV;
printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3233,9 @@ static void __exit u132_hcd_exit(void)
{
struct u132 *u132;
struct u132 *temp;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
u132_exiting += 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
platform_device_unregister(u132->platform_dev);
} platform_driver_unregister(&u132_platform_driver);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4aed305982e..3bb908ca38e 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -827,8 +827,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* If direction is "send", change the packet ID from SETUP (0x2D)
* to OUT (0xE1). Else change it from SETUP to IN (0x69) and
* set Short Packet Detect (SPD) for all data packets.
+ *
+ * 0-length transfers always get treated as "send".
*/
- if (usb_pipeout(urb->pipe))
+ if (usb_pipeout(urb->pipe) || len == 0)
destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
else {
destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +841,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* Build the DATA TDs
*/
while (len > 0) {
- int pktsze = min(len, maxsze);
+ int pktsze = maxsze;
+
+ if (len <= pktsze) { /* The last data packet */
+ pktsze = len;
+ status &= ~TD_CTRL_SPD;
+ }
td = uhci_alloc_td(uhci);
if (!td)
@@ -866,20 +873,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
goto nomem;
*plink = LINK_TO_TD(td);
- /*
- * It's IN if the pipe is an output pipe or we're not expecting
- * data back.
- */
- destination &= ~TD_TOKEN_PID_MASK;
- if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
- destination |= USB_PID_IN;
- else
- destination |= USB_PID_OUT;
-
+ /* Change direction for the status transaction */
+ destination ^= (USB_PID_IN ^ USB_PID_OUT);
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
- status &= ~TD_CTRL_SPD;
-
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0);
@@ -1185,10 +1182,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
}
}
+ /* Did we receive a short packet? */
} else if (len < uhci_expected_length(td_token(td))) {
- /* We received a short packet */
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
+ /* For control transfers, go to the status TD if
+ * this isn't already the last data TD */
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (td->list.next != urbp->td_list.prev)
+ ret = 1;
+ }
+
+ /* For bulk and interrupt, this may be an error */
+ else if (urb->transfer_flags & URB_SHORT_NOT_OK)
ret = -EREMOTEIO;
/* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1213,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
err:
if (ret < 0) {
- /* In case a control transfer gets an error
- * during the setup stage */
- urb->actual_length = max(urb->actual_length, 0);
-
/* Note that the queue has stopped and save
* the next toggle value */
qh->element = UHCI_PTR_TERM;
@@ -1489,9 +1490,25 @@ __acquires(uhci->lock)
{
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+ /* urb->actual_length < 0 means the setup transaction didn't
+ * complete successfully. Either it failed or the URB was
+ * unlinked first. Regardless, don't confuse people with a
+ * negative length. */
+ urb->actual_length = max(urb->actual_length, 0);
+
+ /* Report erroneous short transfers */
+ if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length <
+ urb->transfer_buffer_length &&
+ urb->status == 0))
+ urb->status = -EREMOTEIO;
+ }
+
/* When giving back the first URB in an Isochronous queue,
* reinitialize the QH's iso-related members for the next URB. */
- if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+ else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
urbp->node.prev == &qh->queue &&
urbp->node.next != &qh->queue) {
struct urb *nurb = list_entry(urbp->node.next,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 36502a06f73..d1131a87a5b 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb)
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status >= 0)
- {
+ if (status >= 0) {
//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
@@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb)
||
((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
||
- (urb->status < 0)
+ (status < 0)
);
if (wake_up)
@@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
static void mdc800_usb_write_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status != 0)
- {
- err ("writing command fails (status=%i)", urb->status);
- }
+ if (status != 0)
+ err ("writing command fails (status=%i)", status);
else
- {
mdc800->state=READY;
- }
mdc800->written = 1;
wake_up (&mdc800->write_wait);
}
@@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb)
static void mdc800_usb_download_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status == 0)
- {
+ if (status == 0) {
/* Fill output buffer with these data */
memcpy (mdc800->out, urb->transfer_buffer, 64);
mdc800->out_count=64;
@@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
{
mdc800->state=READY;
}
- }
- else
- {
- err ("request bytes fails (status:%i)", urb->status);
+ } else {
+ err ("request bytes fails (status:%i)", status);
}
mdc800->downloaded = 1;
wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
retval=0;
mdc800->irq_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
- {
- err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+ if (retval) {
+ err ("request USB irq fails (submit_retval=%i).", retval);
errn = -EIO;
goto error_out;
}
@@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
{
size_t left=len, sts=len; /* single transfer size */
char __user *ptr = buf;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
/* Download -> Request new bytes */
mdc800->download_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
- {
- err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+ retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+ if (retval) {
+ err ("Can't submit download urb (retval=%i)",retval);
mutex_unlock(&mdc800->io_lock);
return len-left;
}
@@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
{
size_t i=0;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state != READY)
@@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
mdc800->state=WORKING;
memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
mdc800->write_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
- {
- err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+ retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+ if (retval) {
+ err ("submitting write urb fails (retval=%i)", retval);
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 51bd80d2b8c..768b2c11a23 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = {
#define MTS_DEBUG_INT() \
do { MTS_DEBUG_GOT_HERE(); \
MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
- MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+ MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
mts_debug_dump(context->instance);\
} while(0)
#else
@@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer,
context
);
- transfer->status = 0;
-
res = usb_submit_urb( transfer, GFP_ATOMIC );
if ( unlikely(res) ) {
MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer )
static void mts_data_done( struct urb* transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
if ( context->data_length != transfer->actual_length ) {
context->srb->resid = context->data_length - transfer->actual_length;
- } else if ( unlikely(transfer->status) ) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ } else if ( unlikely(status) ) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
mts_get_status(transfer);
@@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer )
static void mts_command_done( struct urb *transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
- if ( unlikely(transfer->status) ) {
- if (transfer->status == -ENOENT) {
+ if ( unlikely(status) ) {
+ if (status == -ENOENT) {
/* We are being killed */
MTS_DEBUG_GOT_HERE();
context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer )
static void mts_do_sg (struct urb* transfer)
{
struct scatterlist * sg;
+ int status = transfer->status;
MTS_INT_INIT();
MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
- if (unlikely(transfer->status)) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ if (unlikely(status)) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index d72c42e5f22..e9fdbc8997b 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* Structure to hold all of our device specific stuff */
struct adu_device {
- struct semaphore sem; /* locks this structure */
+ struct mutex mtx; /* locks this structure */
struct usb_device* udev; /* save off the usb device pointer */
struct usb_interface* interface;
unsigned char minor; /* the starting minor number for this device */
@@ -178,17 +179,18 @@ static void adu_delete(struct adu_device *dev)
static void adu_interrupt_in_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
spin_lock(&dev->buflock);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) && (status != -ECONNRESET)) {
dbg(1," %s : nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -216,21 +218,22 @@ exit:
wake_up_interruptible(&dev->read_wait);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static void adu_interrupt_out_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) &&
+ (status != -ECONNRESET)) {
dbg(1, " %s :nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -240,7 +243,7 @@ exit:
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +272,8 @@ static int adu_open(struct inode *inode, struct file *file)
}
/* lock this device */
- if ((retval = down_interruptible(&dev->sem))) {
- dbg(2, "%s : sem down failed", __FUNCTION__);
+ if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+ dbg(2, "%s : mutex lock failed", __FUNCTION__);
goto exit_no_device;
}
@@ -299,7 +302,7 @@ static int adu_open(struct inode *inode, struct file *file)
if (retval)
--dev->open_count;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_no_device:
dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +350,7 @@ static int adu_release(struct inode *inode, struct file *file)
}
/* lock our device */
- down(&dev->sem); /* not interruptible */
+ mutex_lock(&dev->mtx); /* not interruptible */
if (dev->open_count <= 0) {
dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +360,7 @@ static int adu_release(struct inode *inode, struct file *file)
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
adu_delete(dev);
dev = NULL;
} else {
@@ -367,7 +370,7 @@ static int adu_release(struct inode *inode, struct file *file)
exit:
if (dev)
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -390,7 +393,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
dev = file->private_data;
dbg(2," %s : dev=%p", __FUNCTION__, dev);
/* lock this object */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mtx))
return -ERESTARTSYS;
/* verify that the device wasn't unplugged */
@@ -522,7 +525,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
@@ -543,7 +546,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
dev = file->private_data;
/* lock this object */
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval)
goto exit_nolock;
@@ -571,9 +574,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
retval = -EINTR;
goto exit;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval) {
retval = bytes_written ? bytes_written : retval;
goto exit_nolock;
@@ -638,7 +641,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_nolock:
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +701,7 @@ static int adu_probe(struct usb_interface *interface,
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock);
dev->udev = udev;
init_waitqueue_head(&dev->read_wait);
@@ -835,16 +838,16 @@ static void adu_disconnect(struct usb_interface *interface)
usb_deregister_dev(interface, &adu_class);
dev->minor = 0;
- down(&dev->sem); /* not interruptible */
+ mutex_lock(&dev->mtx); /* not interruptible */
/* if the device is not opened, then we clean up right now */
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
adu_delete(dev);
} else {
dev->udev = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
}
dev_info(&interface->dev, "ADU device adutux%d now disconnected",
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index cf70c16f0e3..b09c83568c1 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
unsigned long flags;
+ int status = urb->status;
int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
+ dbg("%s - urb shuttingdown with status: %d",
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 42d4e6454a7..df7e1ecc810 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb)
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp;
int ret;
+ int status = urb->status;
+
dbg ("auerswald_ctrlread_wretcomplete called");
- dbg ("complete with status: %d", urb->status);
+ dbg ("complete with status: %d", status);
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if it is possible to advance */
- if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+ if (!auerswald_status_retry(status) || !cp->usbdev) {
/* reuse the buffer */
- err ("control dummy: transmission error %d, can not retry", urb->status);
+ err ("control dummy: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb)
pauerswald_t cp;
pauerscon_t scp;
pauerbuf_t bp = (pauerbuf_t) urb->context;
+ int status = urb->status;
int ret;
+
dbg ("auerswald_ctrlread_complete called");
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if there is valid data in this urb */
- if (urb->status) {
- dbg ("complete with non-zero status: %d", urb->status);
+ if (status) {
+ dbg ("complete with non-zero status: %d", status);
/* should we do a retry? */
- if (!auerswald_status_retry (urb->status)
+ if (!auerswald_status_retry(status)
|| !cp->usbdev
|| (cp->version < AUV_RETRY)
|| (bp->retries >= AU_RETRIES)) {
/* reuse the buffer */
- err ("control read: transmission error %d, can not retry", urb->status);
+ err ("control read: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb)
unsigned int channelid;
unsigned int bytecount;
int ret;
+ int status = urb->status;
pauerbuf_t bp = NULL;
pauerswald_t cp = (pauerswald_t) urb->context;
dbg ("%s called", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index e0f122e131d..538b535e955 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -44,6 +44,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
@@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue;
* ftdi_module_lock exists to protect access to global variables
*
*/
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
static int ftdi_instances = 0;
static struct list_head ftdi_static_list;
/*
@@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref)
dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
usb_put_dev(ftdi->udev);
ftdi->disconnected += 1;
- down(&ftdi_module_lock);
+ mutex_lock(&ftdi_module_lock);
list_del_init(&ftdi->ftdi_list);
ftdi_instances -= 1;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
kfree(ftdi->bulk_in_buffer);
ftdi->bulk_in_buffer = NULL;
}
@@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
static void ftdi_elan_write_bulk_callback(struct urb *urb)
{
struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
- if (urb->status && !(urb->status == -ENOENT || urb->status ==
- -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ int status = urb->status;
+
+ if (status && !(status == -ENOENT || status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
- "d\n", urb, urb->status);
+ "d\n", urb, status);
}
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
@@ -2780,10 +2783,10 @@ static int ftdi_elan_probe(struct usb_interface *interface,
return -ENOMEM;
}
memset(ftdi, 0x00, sizeof(struct usb_ftdi));
- down(&ftdi_module_lock);
+ mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
ftdi_elan_init_kref(ftdi);
init_MUTEX(&ftdi->sw_lock);
ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2912,7 @@ static int __init ftdi_elan_init(void)
int result;
printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
__TIME__, __DATE__);
- init_MUTEX(&ftdi_module_lock);
+ mutex_init(&ftdi_module_lock);
INIT_LIST_HEAD(&ftdi_static_list);
status_queue = create_singlethread_workqueue("ftdi-status-control");
if (!status_queue)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 28548d18671..46d9f27ec17 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -158,9 +158,10 @@ static void iowarrior_callback(struct urb *urb)
int read_idx;
int aux_idx;
int offset;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -213,10 +214,10 @@ static void iowarrior_callback(struct urb *urb)
wake_up_interruptible(&dev->read_wait);
exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
@@ -226,13 +227,15 @@ exit:
static void iowarrior_write_callback(struct urb *urb)
{
struct iowarrior *dev;
+ int status = urb->status;
+
dev = (struct iowarrior *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET || status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ __func__, status);
}
/* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5e950b90c54..8208496dfc6 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -219,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
struct ld_usb *dev = urb->context;
size_t *actual_buffer;
unsigned int next_ring_head;
+ int status = urb->status;
int retval;
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock(&dev->rbsl);
goto resubmit; /* maybe we can recover */
}
@@ -275,14 +276,15 @@ exit:
static void ld_usb_interrupt_out_callback(struct urb *urb)
{
struct ld_usb *dev = urb->context;
+ int status = urb->status;
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN))
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 2ed0daea894..561970b889a 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -742,19 +742,20 @@ exit:
static void tower_interrupt_in_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
int retval;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
- dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+ dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
goto resubmit; /* maybe we can recover */
}
}
@@ -788,7 +789,7 @@ exit:
wake_up_interruptible (&dev->read_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
@@ -798,23 +799,24 @@ exit:
static void tower_interrupt_out_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg(1, "%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 371bf2b1197..aa9bcceabe7 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb)
struct interfacekit *kit = urb->context;
unsigned char *buffer = kit->data;
int i, level, sensor;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb)
schedule_delayed_work(&kit->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
kit->udev->bus->bus_name,
- kit->udev->devpath, status);
+ kit->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 5727e1ea2f9..df0ebcdb9d6 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb)
struct motorcontrol *mc = urb->context;
unsigned char *buffer = mc->data;
int i, level;
- int status;
+ int retval;
+ int status = urb->status;;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb)
schedule_delayed_work(&mc->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&mc->intf->dev,
- "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+ "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
mc->udev->bus->bus_name,
- mc->udev->devpath, status);
+ mc->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 504f7221b0d..71984203271 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -176,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
static void lcd_write_bulk_callback(struct urb *urb)
{
struct usb_lcd *dev;
+ int status = urb->status;
dev = (struct usb_lcd *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
/* free up our allocated buffer */
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index fb321864a92..e901d31e051 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb)
/* some faults are allowed, not required */
if (subcase->expected > 0 && (
- ((urb->status == -subcase->expected /* happened */
- || urb->status == 0)))) /* didn't */
+ ((status == -subcase->expected /* happened */
+ || status == 0)))) /* didn't */
status = 0;
/* sometimes more than one fault is allowed */
else if (subcase->number == 12 && status == -EPIPE)
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 1a60f9c473a..2734fe2b9c4 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -111,12 +111,13 @@ static void async_complete(struct urb *urb)
struct uss720_async_request *rq;
struct parport *pp;
struct parport_uss720_private *priv;
+ int status = urb->status;
rq = urb->context;
priv = rq->priv;
pp = priv->pp;
- if (urb->status) {
- err("async_complete: urb error %d", urb->status);
+ if (status) {
+ err("async_complete: urb error %d", status);
} else if (rq->dr.bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0d3903691e8..b8670905bc3 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2794,16 +2794,14 @@ static void edge_shutdown (struct usb_serial *serial)
dbg ("%s", __FUNCTION__);
- for (i=0; i < serial->num_ports; ++i) {
+ for (i = 0; i < serial->num_ports; ++i) {
edge_port = usb_get_serial_port_data(serial->port[i]);
edge_remove_sysfs_attrs(edge_port->port);
- if (edge_port) {
- edge_buf_free(edge_port->ep_out_buf);
- kfree(edge_port);
- }
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ kfree(usb_get_serial_data(serial));
usb_set_serial_data(serial, NULL);
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 231b584f6d0..01e811becec 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -110,11 +110,6 @@ static void mos7720_interrupt_callback(struct urb *urb)
dbg("%s"," : Entering\n");
- if (!urb) {
- dbg("%s","Invalid Pointer !!!!:\n");
- return;
- }
-
switch (status) {
case 0:
/* success */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 37f41f576d3..f76480f1455 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -436,11 +436,6 @@ static void mos7840_control_callback(struct urb *urb)
int result = 0;
int status = urb->status;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
mos7840_port = (struct moschip_port *)urb->context;
switch (status) {
@@ -525,10 +520,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
int status = urb->status;
dbg("%s", " : Entering\n");
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
switch (status) {
case 0:
@@ -676,11 +667,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct tty_struct *tty;
int status = urb->status;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
if (status) {
dbg("nonzero read bulk status received: %d", status);
return;
@@ -753,11 +739,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
int status = urb->status;
int i;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
mos7840_port = (struct moschip_port *)urb->context;
spin_lock(&mos7840_port->pool_lock);
for (i = 0; i < NUM_URBS; i++) {
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index e7db20343d1..0794ccdebfd 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
/*
USB Driver for Sierra Wireless
- Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -12,10 +12,9 @@
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
*/
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -28,23 +27,98 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#define SWIMS_USB_REQUEST_SetMode 0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
+#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_SET_MODE_Modem 0x0001
+
+/* per port private data */
+#define N_IN_URB 4
+#define N_OUT_URB 4
+#define IN_BUFLEN 4096
+
+static int debug;
+
+enum devicetype {
+ DEVICE_3_PORT = 0,
+ DEVICE_1_PORT = 1,
+ DEVICE_INSTALLER = 2,
+};
+
+int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x00, /* __u8 request */
+ 0x40, /* __u8 request type */
+ swiState, /* __u16 value */
+ 0, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetMode, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
+ eSocMode, /* __u16 value */
+ SWIMS_USB_INDEX_SetMode, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+ int result;
+ struct usb_device *udev;
+
+ udev = usb_get_dev(interface_to_usbdev(iface));
+
+ /* Check if in installer mode */
+ if (id->driver_info == DEVICE_INSTALLER) {
+ dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+ result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+ /*We do not want to bind to the device when in installer mode*/
+ return -EIO;
+ }
+
+ return usb_serial_probe(iface, id);
+}
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+ { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+ { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +132,36 @@ static struct usb_device_id id_table_1port [] = {
static struct usb_device_id id_table_3port [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
{ }
};
static struct usb_driver sierra_driver = {
.name = "sierra",
- .probe = usb_serial_probe,
+ .probe = sierra_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
-static int debug;
-
-/* per port private data */
-#define N_IN_URB 4
-#define N_OUT_URB 4
-#define IN_BUFLEN 4096
-
struct sierra_port_private {
spinlock_t lock; /* lock the structure */
int outstanding_urbs; /* number of out urbs in flight */
@@ -421,7 +496,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
int i;
struct urb *urb;
int result;
- __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -457,12 +531,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
port->tty->low_latency = 1;
- /* set mode to D0 */
- result = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x00, 0x40, set_mode_dzero, 0, NULL,
- 0, USB_CTRL_SET_TIMEOUT);
-
sierra_send_setup(port);
/* start up the interrupt endpoint if we have one */
@@ -510,6 +578,9 @@ static int sierra_startup(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
+ /*Set Device mode to D0 */
+ sierra_set_power_state(serial->dev, 0x0000);
+
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 1628cb25856..9a410b5a6e5 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -46,43 +46,43 @@
*/
int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- int ret;
+ int ret;
- if(srb == NULL)
- return USB_STOR_TRANSPORT_ERROR;
+ if (srb == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+ US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
- switch(srb->device->lun) {
- case 0:
+ switch (srb->device->lun) {
+ case 0:
- /*
- * LUN 0 corresponds to the CompactFlash card reader.
- */
- ret = usb_stor_CB_transport(srb, us);
- break;
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ ret = usb_stor_CB_transport(srb, us);
+ break;
#ifdef CONFIG_USB_STORAGE_SDDR09
- case 1:
+ case 1:
- /*
- * LUN 1 corresponds to the SmartMedia card reader.
- */
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
- /*
- * Set the LUN to 0 (just in case).
- */
- srb->device->lun = 0; us->srb->device->lun = 0;
- ret = sddr09_transport(srb, us);
- srb->device->lun = 1; us->srb->device->lun = 1;
- break;
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->device->lun = 0; us->srb->device->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->device->lun = 1; us->srb->device->lun = 1;
+ break;
#endif
- default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
- ret = USB_STOR_TRANSPORT_ERROR;
- break;
- }
- return ret;
+ default:
+ US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+ ret = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+ return ret;
}
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d35369392fe..dfd42fe9e5f 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb)
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
struct input_dev *dev = onetouch->dev;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb)
input_sync(dev);
resubmit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("can't resubmit intr, %s-%s/input0, retval %d",
onetouch->udev->bus->bus_name,
- onetouch->udev->devpath, status);
+ onetouch->udev->devpath, retval);
}
static int usb_onetouch_open(struct input_dev *dev)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b6bf31a97b6..a624e72f81d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -313,6 +313,13 @@ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
US_SC_DEVICE, US_PR_DEVICE,NULL,
US_FL_NOT_LOCKABLE ),
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV( 0x04b0, 0x0401, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D100",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Andreas Bockhold <andreas@bockionline.de> */
UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
"NIKON",
@@ -1384,6 +1391,17 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
+ "Sierra Wireless",
+ "USB MMC Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
/* Reported by Jaco Kroon <jaco@kroon.co.za>
* The usb-storage module found on the Digitech GNX4 (and supposedly other
* devices) misbehaves and causes a bunch of invalid I/O errors.
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 0c7bf75732e..13990697b5c 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
int node, len, i, j, ret;
u32 mem, chip_id;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
/*
* Map memory-mapped registers.
*/
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index e9bbc3455c9..1b3f6586bc9 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
struct cr_panel *crp;
u8 dev_en;
- crp = kzalloc(sizeof(crp), GFP_KERNEL);
+ crp = kzalloc(sizeof(*crp), GFP_KERNEL);
if (crp == NULL)
return -ENOMEM;
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a4812ad1..b87ea21d3d7 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@ int __init igafb_init(void)
if (fb_get_options("igafb", NULL))
return -ENODEV;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {