aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/acpi_pad.c2
-rw-r--r--drivers/acpi/bus.c2
-rw-r--r--drivers/acpi/hest.c4
-rw-r--r--drivers/acpi/pci_irq.c8
-rw-r--r--drivers/acpi/power_meter.c2
-rw-r--r--drivers/acpi/sbshc.c2
-rw-r--r--drivers/acpi/sleep.c56
-rw-r--r--drivers/ata/pata_pcmcia.c4
-rw-r--r--drivers/base/iommu.c43
-rw-r--r--drivers/base/platform.c24
-rw-r--r--drivers/block/amiflop.c47
-rw-r--r--drivers/block/drbd/drbd_worker.c2
-rw-r--r--drivers/block/hd.c4
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/char/tty_io.c1
-rw-r--r--drivers/clocksource/sh_cmt.c45
-rw-r--r--drivers/clocksource/sh_mtu2.c37
-rw-r--r--drivers/clocksource/sh_tmu.c41
-rw-r--r--drivers/cpufreq/cpufreq.c40
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c48
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c115
-rw-r--r--drivers/cpuidle/governors/menu.c9
-rw-r--r--drivers/dma/shdma.c52
-rw-r--r--drivers/dma/shdma.h4
-rw-r--r--drivers/gpio/it8761e_gpio.c18
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c19
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c30
-rw-r--r--drivers/gpu/drm/ttm/ttm_lock.c5
-rw-r--r--drivers/hid/hid-cherry.c1
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-ntrig.c72
-rw-r--r--drivers/hid/hid-sony.c2
-rw-r--r--drivers/hid/hid-wacom.c1
-rw-r--r--drivers/hid/usbhid/hid-core.c13
-rw-r--r--drivers/hwmon/applesmc.c61
-rw-r--r--drivers/hwmon/asc7621.c63
-rw-r--r--drivers/hwmon/hp_accel.c2
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/ide/ide-cs.c4
-rw-r--r--drivers/input/gameport/gameport.c4
-rw-r--r--drivers/input/joydev.c18
-rw-r--r--drivers/input/joystick/analog.c4
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c6
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c1
-rw-r--r--drivers/input/keyboard/Kconfig48
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/corgikbd.c414
-rw-r--r--drivers/input/keyboard/spitzkbd.c496
-rw-r--r--drivers/input/keyboard/tosakbd.c431
-rw-r--r--drivers/input/misc/ati_remote.c14
-rw-r--r--drivers/input/misc/pcspkr.c6
-rw-r--r--drivers/input/mouse/alps.c1
-rw-r--r--drivers/input/mouse/elantech.c104
-rw-r--r--drivers/input/mouse/elantech.h5
-rw-r--r--drivers/input/mouse/psmouse-base.c32
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/synaptics.c35
-rw-r--r--drivers/input/mouse/synaptics.h4
-rw-r--r--drivers/input/touchscreen/Kconfig16
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ad7877.c15
-rw-r--r--drivers/input/touchscreen/corgi_ts.c385
-rw-r--r--drivers/input/touchscreen/eeti_ts.c56
-rw-r--r--drivers/md/md.c10
-rw-r--r--drivers/md/raid5.c2
-rw-r--r--drivers/media/common/saa7146_fops.c11
-rw-r--r--drivers/media/common/saa7146_video.c8
-rw-r--r--drivers/media/dvb/frontends/stv090x.c4
-rw-r--r--drivers/media/dvb/ttpci/budget.c3
-rw-r--r--drivers/media/video/Kconfig4
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c38
-rw-r--r--drivers/media/video/gspca/sn9c20x.c2
-rw-r--r--drivers/media/video/gspca/spca508.c1
-rw-r--r--drivers/media/video/gspca/spca561.c1
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c2
-rw-r--r--drivers/media/video/hexium_gemini.c3
-rw-r--r--drivers/media/video/hexium_orion.c4
-rw-r--r--drivers/media/video/mx1_camera.c8
-rw-r--r--drivers/media/video/mxb.c17
-rw-r--r--drivers/media/video/omap24xxcam.c2
-rw-r--r--drivers/media/video/pxa_camera.c11
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c2
-rw-r--r--drivers/mfd/wm831x-core.c3
-rw-r--r--drivers/mfd/wm8350-core.c4
-rw-r--r--drivers/misc/vmware_balloon.c4
-rw-r--r--drivers/mmc/host/at91_mci.c2
-rw-r--r--drivers/mmc/host/atmel-mci.c18
-rw-r--r--drivers/mmc/host/mmci.c19
-rw-r--r--drivers/mmc/host/mmci.h6
-rw-r--r--drivers/mmc/host/pxamci.c2
-rw-r--r--drivers/mtd/internal.h0
-rw-r--r--drivers/mtd/mtdbdi.c0
-rw-r--r--drivers/net/a2065.c1
-rw-r--r--drivers/net/ariadne.c1
-rw-r--r--drivers/net/arm/ep93xx_eth.c10
-rw-r--r--drivers/net/e1000e/netdev.c3
-rw-r--r--drivers/net/fec.c2
-rw-r--r--drivers/net/gianfar.c2
-rw-r--r--drivers/net/hydra.c1
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/micrel.c105
-rw-r--r--drivers/net/ppp_generic.c34
-rw-r--r--drivers/net/r8169.c22
-rw-r--r--drivers/net/sb1250-mac.c67
-rw-r--r--drivers/net/usb/Kconfig1
-rw-r--r--drivers/net/usb/dm9601.c2
-rw-r--r--drivers/net/usb/sierra_net.c3
-rw-r--r--drivers/net/veth.c1
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c11
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c3
-rw-r--r--drivers/net/wireless/p54/p54pci.c2
-rw-r--r--drivers/net/zorro8390.c1
-rw-r--r--drivers/oprofile/cpu_buffer.c75
-rw-r--r--drivers/oprofile/oprof.c12
-rw-r--r--drivers/oprofile/oprof.h3
-rw-r--r--drivers/oprofile/timer_int.c78
-rw-r--r--drivers/pci/intel-iommu.c22
-rw-r--r--drivers/pci/setup-bus.c114
-rw-r--r--drivers/pcmcia/Kconfig3
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/cs.c16
-rw-r--r--drivers/pcmcia/ds.c1
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c7
-rw-r--r--drivers/pcmcia/pxa2xx_vpac270.c229
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c26
-rw-r--r--drivers/pnp/resource.c4
-rw-r--r--drivers/s390/block/dasd.c39
-rw-r--r--drivers/s390/block/dasd_3990_erp.c20
-rw-r--r--drivers/s390/block/dasd_alias.c125
-rw-r--r--drivers/s390/block/dasd_devmap.c174
-rw-r--r--drivers/s390/block/dasd_eckd.c116
-rw-r--r--drivers/s390/block/dasd_eckd.h2
-rw-r--r--drivers/s390/block/dasd_int.h49
-rw-r--r--drivers/s390/char/Kconfig3
-rw-r--r--drivers/s390/char/fs3270.c1
-rw-r--r--drivers/s390/char/keyboard.c21
-rw-r--r--drivers/s390/char/vmcp.c38
-rw-r--r--drivers/s390/char/zcore.c4
-rw-r--r--drivers/s390/cio/chsc_sch.c1
-rw-r--r--drivers/s390/cio/cio.c3
-rw-r--r--drivers/s390/cio/css.c8
-rw-r--r--drivers/s390/cio/qdio.h15
-rw-r--r--drivers/s390/cio/qdio_main.c67
-rw-r--r--drivers/s390/cio/qdio_setup.c8
-rw-r--r--drivers/s390/cio/qdio_thinint.c4
-rw-r--r--drivers/s390/crypto/zcrypt_api.c2
-rw-r--r--drivers/s390/net/qeth_core_main.c17
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c1
-rw-r--r--drivers/scsi/advansys.c50
-rw-r--r--drivers/scsi/libiscsi.c2
-rw-r--r--drivers/scsi/libsas/sas_ata.c4
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c4
-rw-r--r--drivers/scsi/scsi_debug.c3
-rw-r--r--drivers/scsi/scsi_error.c15
-rw-r--r--drivers/scsi/sd.c1
-rw-r--r--drivers/scsi/zorro7xx.c1
-rw-r--r--drivers/serial/atmel_serial.c207
-rw-r--r--drivers/serial/imx.c10
-rw-r--r--drivers/serial/mpc52xx_uart.c2
-rw-r--r--drivers/serial/sh-sci.c189
-rw-r--r--drivers/sh/Kconfig24
-rw-r--r--drivers/sh/Makefile2
-rw-r--r--drivers/sh/clk-cpg.c298
-rw-r--r--drivers/sh/clk.c545
-rw-r--r--drivers/sh/intc.c333
-rw-r--r--drivers/spi/pxa2xx_spi.c25
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/gadget/at91_udc.c7
-rw-r--r--drivers/vhost/vhost.c7
-rw-r--r--drivers/video/amifb.c49
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c15
-rw-r--r--drivers/video/cirrusfb.c1
-rw-r--r--drivers/video/fm2fb.c1
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c27
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/mpcore_wdt.c21
-rw-r--r--drivers/xen/manage.c14
-rw-r--r--drivers/zorro/proc.c6
-rw-r--r--drivers/zorro/zorro-driver.c24
-rw-r--r--drivers/zorro/zorro-sysfs.c11
-rw-r--r--drivers/zorro/zorro.c243
191 files changed, 3652 insertions, 3312 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 34f1e1064dbc..f42a03029b7c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SFI) += sfi/
obj-$(CONFIG_PNP) += pnp/
obj-$(CONFIG_ARM_AMBA) += amba/
+obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_XEN) += xen/
# regulators early, since some subsystems rely on them to initialize
@@ -108,7 +109,6 @@ obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VHOST_NET) += vhost/
-obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 19dacfd43163..62122134693b 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -31,7 +31,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#define ACPI_PROCESSOR_AGGREGATOR_CLASS "processor_aggregator"
+#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
static DEFINE_MUTEX(isolated_cpus_lock);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 37132dc2da03..743576bf1bd7 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -527,7 +527,7 @@ int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id,
if (!event_is_open)
return 0;
- event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
+ event = kzalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
if (!event)
return -ENOMEM;
diff --git a/drivers/acpi/hest.c b/drivers/acpi/hest.c
index 4bb18c980ac6..1c527a192872 100644
--- a/drivers/acpi/hest.c
+++ b/drivers/acpi/hest.c
@@ -123,6 +123,10 @@ int acpi_hest_firmware_first_pci(struct pci_dev *pci)
{
acpi_status status = AE_NOT_FOUND;
struct acpi_table_header *hest = NULL;
+
+ if (acpi_disabled)
+ return 0;
+
status = acpi_get_table(ACPI_SIG_HEST, 1, &hest);
if (ACPI_SUCCESS(status)) {
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index b0a71ecee682..e4804fb05e23 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -401,11 +401,13 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
* driver reported one, then use it. Exit in any case.
*/
if (gsi < 0) {
+ u32 dev_gsi;
dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin));
/* Interrupt Line values above 0xF are forbidden */
- if (dev->irq > 0 && (dev->irq <= 0xF)) {
- printk(" - using IRQ %d\n", dev->irq);
- acpi_register_gsi(&dev->dev, dev->irq,
+ if (dev->irq > 0 && (dev->irq <= 0xF) &&
+ (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) {
+ printk(" - using ISA IRQ %d\n", dev->irq);
+ acpi_register_gsi(&dev->dev, dev_gsi,
ACPI_LEVEL_SENSITIVE,
ACPI_ACTIVE_LOW);
return 0;
diff --git a/drivers/acpi/power_meter.c b/drivers/acpi/power_meter.c
index e8c32a49f14e..66f67293341e 100644
--- a/drivers/acpi/power_meter.c
+++ b/drivers/acpi/power_meter.c
@@ -35,7 +35,7 @@
#define ACPI_POWER_METER_NAME "power_meter"
ACPI_MODULE_NAME(ACPI_POWER_METER_NAME);
#define ACPI_POWER_METER_DEVICE_NAME "Power Meter"
-#define ACPI_POWER_METER_CLASS "power_meter_resource"
+#define ACPI_POWER_METER_CLASS "pwr_meter_resource"
#define NUM_SENSORS 17
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 36704b887ccf..f8be23b6c129 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -18,7 +18,7 @@
#define PREFIX "ACPI: "
-#define ACPI_SMB_HC_CLASS "smbus_host_controller"
+#define ACPI_SMB_HC_CLASS "smbus_host_ctl"
#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
struct acpi_smb_hc {
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index f74834a544fd..baa76bbf244a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -450,6 +450,38 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
},
},
{
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Lenovo ThinkPad T410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T410"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Lenovo ThinkPad T510",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T510"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Lenovo ThinkPad W510",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W510"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Lenovo ThinkPad X201[s]",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201"),
+ },
+ },
+ {
.callback = init_old_suspend_ordering,
.ident = "Panasonic CF51-2L",
.matches = {
@@ -458,6 +490,30 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"),
},
},
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Dell Studio 1558",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1558"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Dell Studio 1557",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
+ },
+ },
+ {
+ .callback = init_set_sci_en_on_resume,
+ .ident = "Dell Studio 1555",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1555"),
+ },
+ },
{},
};
#endif /* CONFIG_SUSPEND */
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 4164dd244dd0..d94b8f0bd743 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -424,7 +424,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
- PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
@@ -446,7 +446,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
diff --git a/drivers/base/iommu.c b/drivers/base/iommu.c
index 8ad4ffea6920..6e6b6a11b3ce 100644
--- a/drivers/base/iommu.c
+++ b/drivers/base/iommu.c
@@ -80,20 +80,6 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev)
}
EXPORT_SYMBOL_GPL(iommu_detach_device);
-int iommu_map_range(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot)
-{
- return iommu_ops->map(domain, iova, paddr, size, prot);
-}
-EXPORT_SYMBOL_GPL(iommu_map_range);
-
-void iommu_unmap_range(struct iommu_domain *domain, unsigned long iova,
- size_t size)
-{
- iommu_ops->unmap(domain, iova, size);
-}
-EXPORT_SYMBOL_GPL(iommu_unmap_range);
-
phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain,
unsigned long iova)
{
@@ -107,3 +93,32 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
return iommu_ops->domain_has_cap(domain, cap);
}
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
+
+int iommu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, int gfp_order, int prot)
+{
+ unsigned long invalid_mask;
+ size_t size;
+
+ size = 0x1000UL << gfp_order;
+ invalid_mask = size - 1;
+
+ BUG_ON((iova | paddr) & invalid_mask);
+
+ return iommu_ops->map(domain, iova, paddr, gfp_order, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map);
+
+int iommu_unmap(struct iommu_domain *domain, unsigned long iova, int gfp_order)
+{
+ unsigned long invalid_mask;
+ size_t size;
+
+ size = 0x1000UL << gfp_order;
+ invalid_mask = size - 1;
+
+ BUG_ON(iova & invalid_mask);
+
+ return iommu_ops->unmap(domain, iova, gfp_order);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 4b4b565c835f..765bcf0df3bb 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(platform_device_alloc);
* released.
*/
int platform_device_add_resources(struct platform_device *pdev,
- struct resource *res, unsigned int num)
+ const struct resource *res, unsigned int num)
{
struct resource *r;
@@ -367,7 +367,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
*/
struct platform_device *platform_device_register_simple(const char *name,
int id,
- struct resource *res,
+ const struct resource *res,
unsigned int num)
{
struct platform_device *pdev;
@@ -1254,6 +1254,26 @@ static int __init early_platform_driver_probe_id(char *class_str,
}
if (match) {
+ /*
+ * Set up a sensible init_name to enable
+ * dev_name() and others to be used before the
+ * rest of the driver core is initialized.
+ */
+ if (!match->dev.init_name && slab_is_available()) {
+ if (match->id != -1)
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s.%d",
+ match->name,
+ match->id);
+ else
+ match->dev.init_name =
+ kasprintf(GFP_KERNEL, "%s",
+ match->name);
+
+ if (!match->dev.init_name)
+ return -ENOMEM;
+ }
+
if (epdrv->pdrv->probe(match))
pr_warning("%s: unable to probe %s early.\n",
class_str, match->name);
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 0182a22c423a..832798aa14f6 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -66,6 +66,7 @@
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -1696,34 +1697,18 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
return get_disk(unit[drive].gendisk);
}
-static int __init amiga_floppy_init(void)
+static int __init amiga_floppy_probe(struct platform_device *pdev)
{
int i, ret;
- if (!MACH_IS_AMIGA)
- return -ENODEV;
-
- if (!AMIGAHW_PRESENT(AMI_FLOPPY))
- return -ENODEV;
-
if (register_blkdev(FLOPPY_MAJOR,"fd"))
return -EBUSY;
- /*
- * We request DSKPTR, DSKLEN and DSKDATA only, because the other
- * floppy registers are too spreaded over the custom register space
- */
- ret = -EBUSY;
- if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) {
- printk("fd: cannot get floppy registers\n");
- goto out_blkdev;
- }
-
ret = -ENOMEM;
if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) ==
NULL) {
printk("fd: cannot get chip mem buffer\n");
- goto out_memregion;
+ goto out_blkdev;
}
ret = -EBUSY;
@@ -1792,18 +1777,13 @@ out_irq2:
free_irq(IRQ_AMIGA_DSKBLK, NULL);
out_irq:
amiga_chip_free(raw_buf);
-out_memregion:
- release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
out_blkdev:
unregister_blkdev(FLOPPY_MAJOR,"fd");
return ret;
}
-module_init(amiga_floppy_init);
-#ifdef MODULE
-
#if 0 /* not safe to unload */
-void cleanup_module(void)
+static int __exit amiga_floppy_remove(struct platform_device *pdev)
{
int i;
@@ -1820,12 +1800,25 @@ void cleanup_module(void)
custom.dmacon = DMAF_DISK; /* disable DMA */
amiga_chip_free(raw_buf);
blk_cleanup_queue(floppy_queue);
- release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
unregister_blkdev(FLOPPY_MAJOR, "fd");
}
#endif
-#else
+static struct platform_driver amiga_floppy_driver = {
+ .driver = {
+ .name = "amiga-floppy",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amiga_floppy_init(void)
+{
+ return platform_driver_probe(&amiga_floppy_driver, amiga_floppy_probe);
+}
+
+module_init(amiga_floppy_init);
+
+#ifndef MODULE
static int __init amiga_floppy_setup (char *str)
{
int n;
@@ -1840,3 +1833,5 @@ static int __init amiga_floppy_setup (char *str)
__setup("floppy=", amiga_floppy_setup);
#endif
+
+MODULE_ALIAS("platform:amiga-floppy");
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 44bf6d11197e..d48a1dfd7b24 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -235,7 +235,7 @@ void drbd_endio_pri(struct bio *bio, int error)
if (unlikely(error)) {
what = (bio_data_dir(bio) == WRITE)
? write_completed_with_error
- : (bio_rw(bio) == READA)
+ : (bio_rw(bio) == READ)
? read_completed_with_error
: read_ahead_completed_with_error;
} else
diff --git a/drivers/block/hd.c b/drivers/block/hd.c
index 034e6dfc878c..81c78b3ce2df 100644
--- a/drivers/block/hd.c
+++ b/drivers/block/hd.c
@@ -164,12 +164,12 @@ unsigned long read_timer(void)
unsigned long t, flags;
int i;
- spin_lock_irqsave(&i8253_lock, flags);
+ raw_spin_lock_irqsave(&i8253_lock, flags);
t = jiffies * 11932;
outb_p(0, 0x43);
i = inb_p(0x40);
i |= inb(0x40) << 8;
- spin_unlock_irqrestore(&i8253_lock, flags);
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
return(t - i);
}
#endif
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 8dfd24721a82..78a62ebe75c7 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -627,7 +627,6 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id)
char data;
int char_count;
int save_cnt;
- int len;
/* determine the channel and change to that context */
channel = (u_short) (base_addr[CyLICR] >> 2);
@@ -1528,7 +1527,6 @@ static int
cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned long val;
struct cyclades_port *info = tty->driver_data;
int ret_val = 0;
void __user *argp = (void __user *)arg;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 59de2525d303..d4e8b213a462 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -289,7 +289,7 @@ static struct sysrq_key_op sysrq_showstate_blocked_op = {
static void sysrq_ftrace_dump(int key, struct tty_struct *tty)
{
- ftrace_dump();
+ ftrace_dump(DUMP_ALL);
}
static struct sysrq_key_op sysrq_ftrace_dump_op = {
.handler = sysrq_ftrace_dump,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 6da962c9b21c..d71f0fc34b46 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1875,6 +1875,7 @@ got_driver:
*/
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
+ unlock_kernel();
goto retry_open;
}
unlock_kernel();
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 744f748cc84b..f6677cb19789 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -150,13 +150,12 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
{
- struct sh_timer_config *cfg = p->pdev->dev.platform_data;
int ret;
/* enable clock */
ret = clk_enable(p->clk);
if (ret) {
- pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
+ dev_err(&p->pdev->dev, "cannot enable clock\n");
return ret;
}
@@ -279,7 +278,7 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p,
delay = 1;
if (!delay)
- pr_warning("sh_cmt: too long delay\n");
+ dev_warn(&p->pdev->dev, "too long delay\n");
} while (delay);
}
@@ -289,7 +288,7 @@ static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta)
unsigned long flags;
if (delta > p->max_match_value)
- pr_warning("sh_cmt: delta out of range\n");
+ dev_warn(&p->pdev->dev, "delta out of range\n");
spin_lock_irqsave(&p->lock, flags);
p->next_match_value = delta;
@@ -451,7 +450,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
cs->resume = sh_cmt_clocksource_resume;
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
- pr_info("sh_cmt: %s used as clock source\n", cs->name);
+ dev_info(&p->pdev->dev, "used as clock source\n");
clocksource_register(cs);
return 0;
}
@@ -497,13 +496,11 @@ static void sh_cmt_clock_event_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- pr_info("sh_cmt: %s used for periodic clock events\n",
- ced->name);
+ dev_info(&p->pdev->dev, "used for periodic clock events\n");
sh_cmt_clock_event_start(p, 1);
break;
case CLOCK_EVT_MODE_ONESHOT:
- pr_info("sh_cmt: %s used for oneshot clock events\n",
- ced->name);
+ dev_info(&p->pdev->dev, "used for oneshot clock events\n");
sh_cmt_clock_event_start(p, 0);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
@@ -544,7 +541,7 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
ced->set_next_event = sh_cmt_clock_event_next;
ced->set_mode = sh_cmt_clock_event_mode;
- pr_info("sh_cmt: %s used for clock events\n", ced->name);
+ dev_info(&p->pdev->dev, "used for clock events\n");
clockevents_register_device(ced);
}
@@ -601,22 +598,27 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
/* map memory, let mapbase point to our channel */
p->mapbase = ioremap_nocache(res->start, resource_size(res));
if (p->mapbase == NULL) {
- pr_err("sh_cmt: failed to remap I/O memory\n");
+ dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
goto err0;
}
/* request irq using setup_irq() (too early for request_irq()) */
- p->irqaction.name = cfg->name;
+ p->irqaction.name = dev_name(&p->pdev->dev);
p->irqaction.handler = sh_cmt_interrupt;
p->irqaction.dev_id = p;
- p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+ p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
+ IRQF_IRQPOLL | IRQF_NOBALANCING;
/* get hold of clock */
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ p->clk = clk_get(&p->pdev->dev, "cmt_fck");
if (IS_ERR(p->clk)) {
- pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
- ret = PTR_ERR(p->clk);
- goto err1;
+ dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
+ p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ if (IS_ERR(p->clk)) {
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
+ }
}
if (resource_size(res) == 6) {
@@ -629,17 +631,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
p->clear_bits = ~0xc000;
}
- ret = sh_cmt_register(p, cfg->name,
+ ret = sh_cmt_register(p, (char *)dev_name(&p->pdev->dev),
cfg->clockevent_rating,
cfg->clocksource_rating);
if (ret) {
- pr_err("sh_cmt: registration failed\n");
+ dev_err(&p->pdev->dev, "registration failed\n");
goto err1;
}
ret = setup_irq(irq, &p->irqaction);
if (ret) {
- pr_err("sh_cmt: failed to request irq %d\n", irq);
+ dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
goto err1;
}
@@ -654,11 +656,10 @@ err0:
static int __devinit sh_cmt_probe(struct platform_device *pdev)
{
struct sh_cmt_priv *p = platform_get_drvdata(pdev);
- struct sh_timer_config *cfg = pdev->dev.platform_data;
int ret;
if (p) {
- pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name);
+ dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 5fb78bfd73bb..ef7a5be8a09f 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -119,13 +119,12 @@ static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start)
static int sh_mtu2_enable(struct sh_mtu2_priv *p)
{
- struct sh_timer_config *cfg = p->pdev->dev.platform_data;
int ret;
/* enable clock */
ret = clk_enable(p->clk);
if (ret) {
- pr_err("sh_mtu2: cannot enable clock \"%s\"\n", cfg->clk);
+ dev_err(&p->pdev->dev, "cannot enable clock\n");
return ret;
}
@@ -194,8 +193,7 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- pr_info("sh_mtu2: %s used for periodic clock events\n",
- ced->name);
+ dev_info(&p->pdev->dev, "used for periodic clock events\n");
sh_mtu2_enable(p);
break;
case CLOCK_EVT_MODE_UNUSED:
@@ -222,13 +220,13 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
ced->cpumask = cpumask_of(0);
ced->set_mode = sh_mtu2_clock_event_mode;
- pr_info("sh_mtu2: %s used for clock events\n", ced->name);
+ dev_info(&p->pdev->dev, "used for clock events\n");
clockevents_register_device(ced);
ret = setup_irq(p->irqaction.irq, &p->irqaction);
if (ret) {
- pr_err("sh_mtu2: failed to request irq %d\n",
- p->irqaction.irq);
+ dev_err(&p->pdev->dev, "failed to request irq %d\n",
+ p->irqaction.irq);
return;
}
}
@@ -274,26 +272,32 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
/* map memory, let mapbase point to our channel */
p->mapbase = ioremap_nocache(res->start, resource_size(res));
if (p->mapbase == NULL) {
- pr_err("sh_mtu2: failed to remap I/O memory\n");
+ dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
goto err0;
}
/* setup data for setup_irq() (too early for request_irq()) */
- p->irqaction.name = cfg->name;
+ p->irqaction.name = dev_name(&p->pdev->dev);
p->irqaction.handler = sh_mtu2_interrupt;
p->irqaction.dev_id = p;
p->irqaction.irq = irq;
- p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+ p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
+ IRQF_IRQPOLL | IRQF_NOBALANCING;
/* get hold of clock */
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
if (IS_ERR(p->clk)) {
- pr_err("sh_mtu2: cannot get clock \"%s\"\n", cfg->clk);
- ret = PTR_ERR(p->clk);
- goto err1;
+ dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
+ p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ if (IS_ERR(p->clk)) {
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
+ }
}
- return sh_mtu2_register(p, cfg->name, cfg->clockevent_rating);
+ return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
+ cfg->clockevent_rating);
err1:
iounmap(p->mapbase);
err0:
@@ -303,11 +307,10 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
static int __devinit sh_mtu2_probe(struct platform_device *pdev)
{
struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
- struct sh_timer_config *cfg = pdev->dev.platform_data;
int ret;
if (p) {
- pr_info("sh_mtu2: %s kept as earlytimer\n", cfg->name);
+ dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index fc9ff1e5b770..8e44e14ec4c2 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -107,13 +107,12 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
static int sh_tmu_enable(struct sh_tmu_priv *p)
{
- struct sh_timer_config *cfg = p->pdev->dev.platform_data;
int ret;
/* enable clock */
ret = clk_enable(p->clk);
if (ret) {
- pr_err("sh_tmu: cannot enable clock \"%s\"\n", cfg->clk);
+ dev_err(&p->pdev->dev, "cannot enable clock\n");
return ret;
}
@@ -229,7 +228,7 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
cs->disable = sh_tmu_clocksource_disable;
cs->mask = CLOCKSOURCE_MASK(32);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
- pr_info("sh_tmu: %s used as clock source\n", cs->name);
+ dev_info(&p->pdev->dev, "used as clock source\n");
clocksource_register(cs);
return 0;
}
@@ -277,13 +276,11 @@ static void sh_tmu_clock_event_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- pr_info("sh_tmu: %s used for periodic clock events\n",
- ced->name);
+ dev_info(&p->pdev->dev, "used for periodic clock events\n");
sh_tmu_clock_event_start(p, 1);
break;
case CLOCK_EVT_MODE_ONESHOT:
- pr_info("sh_tmu: %s used for oneshot clock events\n",
- ced->name);
+ dev_info(&p->pdev->dev, "used for oneshot clock events\n");
sh_tmu_clock_event_start(p, 0);
break;
case CLOCK_EVT_MODE_UNUSED:
@@ -324,13 +321,13 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
ced->set_next_event = sh_tmu_clock_event_next;
ced->set_mode = sh_tmu_clock_event_mode;
- pr_info("sh_tmu: %s used for clock events\n", ced->name);
+ dev_info(&p->pdev->dev, "used for clock events\n");
clockevents_register_device(ced);
ret = setup_irq(p->irqaction.irq, &p->irqaction);
if (ret) {
- pr_err("sh_tmu: failed to request irq %d\n",
- p->irqaction.irq);
+ dev_err(&p->pdev->dev, "failed to request irq %d\n",
+ p->irqaction.irq);
return;
}
}
@@ -379,26 +376,31 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
/* map memory, let mapbase point to our channel */
p->mapbase = ioremap_nocache(res->start, resource_size(res));
if (p->mapbase == NULL) {
- pr_err("sh_tmu: failed to remap I/O memory\n");
+ dev_err(&p->pdev->dev, "failed to remap I/O memory\n");
goto err0;
}
/* setup data for setup_irq() (too early for request_irq()) */
- p->irqaction.name = cfg->name;
+ p->irqaction.name = dev_name(&p->pdev->dev);
p->irqaction.handler = sh_tmu_interrupt;
p->irqaction.dev_id = p;
p->irqaction.irq = irq;
- p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
+ p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | \
+ IRQF_IRQPOLL | IRQF_NOBALANCING;
/* get hold of clock */
- p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ p->clk = clk_get(&p->pdev->dev, "tmu_fck");
if (IS_ERR(p->clk)) {
- pr_err("sh_tmu: cannot get clock \"%s\"\n", cfg->clk);
- ret = PTR_ERR(p->clk);
- goto err1;
+ dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
+ p->clk = clk_get(&p->pdev->dev, cfg->clk);
+ if (IS_ERR(p->clk)) {
+ dev_err(&p->pdev->dev, "cannot get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err1;
+ }
}
- return sh_tmu_register(p, cfg->name,
+ return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
cfg->clockevent_rating,
cfg->clocksource_rating);
err1:
@@ -410,11 +412,10 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
static int __devinit sh_tmu_probe(struct platform_device *pdev)
{
struct sh_tmu_priv *p = platform_get_drvdata(pdev);
- struct sh_timer_config *cfg = pdev->dev.platform_data;
int ret;
if (p) {
- pr_info("sh_tmu: %s kept as earlytimer\n", cfg->name);
+ dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 75d293eeb3ee..063b2184caf5 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -662,32 +662,20 @@ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf)
return sprintf(buf, "%u\n", policy->cpuinfo.max_freq);
}
-#define define_one_ro(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-#define define_one_ro0400(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0400, show_##_name, NULL)
-
-#define define_one_rw(_name) \
-static struct freq_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_ro0400(cpuinfo_cur_freq);
-define_one_ro(cpuinfo_min_freq);
-define_one_ro(cpuinfo_max_freq);
-define_one_ro(cpuinfo_transition_latency);
-define_one_ro(scaling_available_governors);
-define_one_ro(scaling_driver);
-define_one_ro(scaling_cur_freq);
-define_one_ro(bios_limit);
-define_one_ro(related_cpus);
-define_one_ro(affected_cpus);
-define_one_rw(scaling_min_freq);
-define_one_rw(scaling_max_freq);
-define_one_rw(scaling_governor);
-define_one_rw(scaling_setspeed);
+cpufreq_freq_attr_ro_perm(cpuinfo_cur_freq, 0400);
+cpufreq_freq_attr_ro(cpuinfo_min_freq);
+cpufreq_freq_attr_ro(cpuinfo_max_freq);
+cpufreq_freq_attr_ro(cpuinfo_transition_latency);
+cpufreq_freq_attr_ro(scaling_available_governors);
+cpufreq_freq_attr_ro(scaling_driver);
+cpufreq_freq_attr_ro(scaling_cur_freq);
+cpufreq_freq_attr_ro(bios_limit);
+cpufreq_freq_attr_ro(related_cpus);
+cpufreq_freq_attr_ro(affected_cpus);
+cpufreq_freq_attr_rw(scaling_min_freq);
+cpufreq_freq_attr_rw(scaling_max_freq);
+cpufreq_freq_attr_rw(scaling_governor);
+cpufreq_freq_attr_rw(scaling_setspeed);
static struct attribute *default_attrs[] = {
&cpuinfo_min_freq.attr,
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 3a147874a465..526bfbf69611 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -178,12 +178,8 @@ static ssize_t show_sampling_rate_min(struct kobject *kobj,
return sprintf(buf, "%u\n", min_sampling_rate);
}
-#define define_one_ro(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(sampling_rate_max);
-define_one_ro(sampling_rate_min);
+define_one_global_ro(sampling_rate_max);
+define_one_global_ro(sampling_rate_min);
/* cpufreq_conservative Governor Tunables */
#define show_one(file_name, object) \
@@ -221,12 +217,8 @@ show_one_old(freq_step);
show_one_old(sampling_rate_min);
show_one_old(sampling_rate_max);
-#define define_one_ro_old(object, _name) \
-static struct freq_attr object = \
-__ATTR(_name, 0444, show_##_name##_old, NULL)
-
-define_one_ro_old(sampling_rate_min_old, sampling_rate_min);
-define_one_ro_old(sampling_rate_max_old, sampling_rate_max);
+cpufreq_freq_attr_ro_old(sampling_rate_min);
+cpufreq_freq_attr_ro_old(sampling_rate_max);
/*** delete after deprecation time ***/
@@ -364,16 +356,12 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b,
return count;
}
-#define define_one_rw(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_rw(sampling_rate);
-define_one_rw(sampling_down_factor);
-define_one_rw(up_threshold);
-define_one_rw(down_threshold);
-define_one_rw(ignore_nice_load);
-define_one_rw(freq_step);
+define_one_global_rw(sampling_rate);
+define_one_global_rw(sampling_down_factor);
+define_one_global_rw(up_threshold);
+define_one_global_rw(down_threshold);
+define_one_global_rw(ignore_nice_load);
+define_one_global_rw(freq_step);
static struct attribute *dbs_attributes[] = {
&sampling_rate_max.attr,
@@ -409,16 +397,12 @@ write_one_old(down_threshold);
write_one_old(ignore_nice_load);
write_one_old(freq_step);
-#define define_one_rw_old(object, _name) \
-static struct freq_attr object = \
-__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
-
-define_one_rw_old(sampling_rate_old, sampling_rate);
-define_one_rw_old(sampling_down_factor_old, sampling_down_factor);
-define_one_rw_old(up_threshold_old, up_threshold);
-define_one_rw_old(down_threshold_old, down_threshold);
-define_one_rw_old(ignore_nice_load_old, ignore_nice_load);
-define_one_rw_old(freq_step_old, freq_step);
+cpufreq_freq_attr_rw_old(sampling_rate);
+cpufreq_freq_attr_rw_old(sampling_down_factor);
+cpufreq_freq_attr_rw_old(up_threshold);
+cpufreq_freq_attr_rw_old(down_threshold);
+cpufreq_freq_attr_rw_old(ignore_nice_load);
+cpufreq_freq_attr_rw_old(freq_step);
static struct attribute *dbs_attributes_old[] = {
&sampling_rate_max_old.attr,
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index bd444dc93cf2..e1314212d8d4 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -73,6 +73,7 @@ enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
struct cpu_dbs_info_s {
cputime64_t prev_cpu_idle;
+ cputime64_t prev_cpu_iowait;
cputime64_t prev_cpu_wall;
cputime64_t prev_cpu_nice;
struct cpufreq_policy *cur_policy;
@@ -108,6 +109,7 @@ static struct dbs_tuners {
unsigned int down_differential;
unsigned int ignore_nice;
unsigned int powersave_bias;
+ unsigned int io_is_busy;
} dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
.down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL,
@@ -148,6 +150,16 @@ static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall)
return idle_time;
}
+static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall)
+{
+ u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
+
+ if (iowait_time == -1ULL)
+ return 0;
+
+ return iowait_time;
+}
+
/*
* Find right freq to be set now with powersave_bias on.
* Returns the freq_hi to be used right now and will set freq_hi_jiffies,
@@ -234,12 +246,8 @@ static ssize_t show_sampling_rate_min(struct kobject *kobj,
return sprintf(buf, "%u\n", min_sampling_rate);
}
-#define define_one_ro(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0444, show_##_name, NULL)
-
-define_one_ro(sampling_rate_max);
-define_one_ro(sampling_rate_min);
+define_one_global_ro(sampling_rate_max);
+define_one_global_ro(sampling_rate_min);
/* cpufreq_ondemand Governor Tunables */
#define show_one(file_name, object) \
@@ -249,6 +257,7 @@ static ssize_t show_##file_name \
return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
}
show_one(sampling_rate, sampling_rate);
+show_one(io_is_busy, io_is_busy);
show_one(up_threshold, up_threshold);
show_one(ignore_nice_load, ignore_nice);
show_one(powersave_bias, powersave_bias);
@@ -274,12 +283,8 @@ show_one_old(powersave_bias);
show_one_old(sampling_rate_min);
show_one_old(sampling_rate_max);
-#define define_one_ro_old(object, _name) \
-static struct freq_attr object = \
-__ATTR(_name, 0444, show_##_name##_old, NULL)
-
-define_one_ro_old(sampling_rate_min_old, sampling_rate_min);
-define_one_ro_old(sampling_rate_max_old, sampling_rate_max);
+cpufreq_freq_attr_ro_old(sampling_rate_min);
+cpufreq_freq_attr_ro_old(sampling_rate_max);
/*** delete after deprecation time ***/
@@ -299,6 +304,23 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
return count;
}
+static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.io_is_busy = !!input;
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
static ssize_t store_up_threshold(struct kobject *a, struct attribute *b,
const char *buf, size_t count)
{
@@ -376,14 +398,11 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b,
return count;
}
-#define define_one_rw(_name) \
-static struct global_attr _name = \
-__ATTR(_name, 0644, show_##_name, store_##_name)
-
-define_one_rw(sampling_rate);
-define_one_rw(up_threshold);
-define_one_rw(ignore_nice_load);
-define_one_rw(powersave_bias);
+define_one_global_rw(sampling_rate);
+define_one_global_rw(io_is_busy);
+define_one_global_rw(up_threshold);
+define_one_global_rw(ignore_nice_load);
+define_one_global_rw(powersave_bias);
static struct attribute *dbs_attributes[] = {
&sampling_rate_max.attr,
@@ -392,6 +411,7 @@ static struct attribute *dbs_attributes[] = {
&up_threshold.attr,
&ignore_nice_load.attr,
&powersave_bias.attr,
+ &io_is_busy.attr,
NULL
};
@@ -415,14 +435,10 @@ write_one_old(up_threshold);
write_one_old(ignore_nice_load);
write_one_old(powersave_bias);
-#define define_one_rw_old(object, _name) \
-static struct freq_attr object = \
-__ATTR(_name, 0644, show_##_name##_old, store_##_name##_old)
-
-define_one_rw_old(sampling_rate_old, sampling_rate);
-define_one_rw_old(up_threshold_old, up_threshold);
-define_one_rw_old(ignore_nice_load_old, ignore_nice_load);
-define_one_rw_old(powersave_bias_old, powersave_bias);
+cpufreq_freq_attr_rw_old(sampling_rate);
+cpufreq_freq_attr_rw_old(up_threshold);
+cpufreq_freq_attr_rw_old(ignore_nice_load);
+cpufreq_freq_attr_rw_old(powersave_bias);
static struct attribute *dbs_attributes_old[] = {
&sampling_rate_max_old.attr,
@@ -470,14 +486,15 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
- cputime64_t cur_wall_time, cur_idle_time;
- unsigned int idle_time, wall_time;
+ cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time;
+ unsigned int idle_time, wall_time, iowait_time;
unsigned int load, load_freq;
int freq_avg;
j_dbs_info = &per_cpu(od_cpu_dbs_info, j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time);
+ cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time);
wall_time = (unsigned int) cputime64_sub(cur_wall_time,
j_dbs_info->prev_cpu_wall);
@@ -487,6 +504,10 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
j_dbs_info->prev_cpu_idle);
j_dbs_info->prev_cpu_idle = cur_idle_time;
+ iowait_time = (unsigned int) cputime64_sub(cur_iowait_time,
+ j_dbs_info->prev_cpu_iowait);
+ j_dbs_info->prev_cpu_iowait = cur_iowait_time;
+
if (dbs_tuners_ins.ignore_nice) {
cputime64_t cur_nice;
unsigned long cur_nice_jiffies;
@@ -504,6 +525,16 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
idle_time += jiffies_to_usecs(cur_nice_jiffies);
}
+ /*
+ * For the purpose of ondemand, waiting for disk IO is an
+ * indication that you're performance critical, and not that
+ * the system is actually idle. So subtract the iowait time
+ * from the cpu idle time.
+ */
+
+ if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time)
+ idle_time -= iowait_time;
+
if (unlikely(!wall_time || wall_time < idle_time))
continue;
@@ -617,6 +648,29 @@ static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
cancel_delayed_work_sync(&dbs_info->work);
}
+/*
+ * Not all CPUs want IO time to be accounted as busy; this dependson how
+ * efficient idling at a higher frequency/voltage is.
+ * Pavel Machek says this is not so for various generations of AMD and old
+ * Intel systems.
+ * Mike Chan (androidlcom) calis this is also not true for ARM.
+ * Because of this, whitelist specific known (series) of CPUs by default, and
+ * leave all others up to the user.
+ */
+static int should_io_be_busy(void)
+{
+#if defined(CONFIG_X86)
+ /*
+ * For Intel, Core 2 (model 15) andl later have an efficient idle.
+ */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+ boot_cpu_data.x86 == 6 &&
+ boot_cpu_data.x86_model >= 15)
+ return 1;
+#endif
+ return 0;
+}
+
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
unsigned int event)
{
@@ -679,6 +733,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_tuners_ins.sampling_rate =
max(min_sampling_rate,
latency * LATENCY_MULTIPLIER);
+ dbs_tuners_ins.io_is_busy = should_io_be_busy();
}
mutex_unlock(&dbs_mutex);
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 1aea7157d8ff..f8e57c6303f2 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -100,7 +100,6 @@ struct menu_device {
int needs_update;
unsigned int expected_us;
- unsigned int measured_us;
u64 predicted_us;
unsigned int exit_us;
unsigned int bucket;
@@ -187,14 +186,14 @@ static int menu_select(struct cpuidle_device *dev)
int i;
int multiplier;
- data->last_state_idx = 0;
- data->exit_us = 0;
-
if (data->needs_update) {
menu_update(dev);
data->needs_update = 0;
}
+ data->last_state_idx = 0;
+ data->exit_us = 0;
+
/* Special case when user has set very strict latency requirement */
if (unlikely(latency_req == 0))
return 0;
@@ -294,7 +293,7 @@ static void menu_update(struct cpuidle_device *dev)
new_factor = data->correction_factor[data->bucket]
* (DECAY - 1) / DECAY;
- if (data->expected_us > 0 && data->measured_us < MAX_INTERESTING)
+ if (data->expected_us > 0 && measured_us < MAX_INTERESTING)
new_factor += RESOLUTION * measured_us / data->expected_us;
else
/*
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index 7cc31b3f40d8..323afef77802 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -26,8 +26,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-
-#include <asm/dmaengine.h>
+#include <linux/sh_dma.h>
#include "shdma.h"
@@ -45,7 +44,7 @@ enum sh_dmae_desc_status {
#define LOG2_DEFAULT_XFER_SIZE 2
/* A bitmask with bits enough for enum sh_dmae_slave_chan_id */
-static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SHDMA_SLAVE_NUMBER)];
+static unsigned long sh_dmae_slave_used[BITS_TO_LONGS(SH_DMA_SLAVE_NUMBER)];
static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all);
@@ -190,7 +189,7 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
struct sh_dmae_device *shdev = container_of(sh_chan->common.device,
struct sh_dmae_device, common);
struct sh_dmae_pdata *pdata = shdev->pdata;
- struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
+ const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
int shift = chan_pdata->dmars_bit;
@@ -266,8 +265,8 @@ static struct sh_desc *sh_dmae_get_desc(struct sh_dmae_chan *sh_chan)
return NULL;
}
-static struct sh_dmae_slave_config *sh_dmae_find_slave(
- struct sh_dmae_chan *sh_chan, enum sh_dmae_slave_chan_id slave_id)
+static const struct sh_dmae_slave_config *sh_dmae_find_slave(
+ struct sh_dmae_chan *sh_chan, struct sh_dmae_slave *param)
{
struct dma_device *dma_dev = sh_chan->common.device;
struct sh_dmae_device *shdev = container_of(dma_dev,
@@ -275,11 +274,11 @@ static struct sh_dmae_slave_config *sh_dmae_find_slave(
struct sh_dmae_pdata *pdata = shdev->pdata;
int i;
- if ((unsigned)slave_id >= SHDMA_SLAVE_NUMBER)
+ if (param->slave_id >= SH_DMA_SLAVE_NUMBER)
return NULL;
for (i = 0; i < pdata->slave_num; i++)
- if (pdata->slave[i].slave_id == slave_id)
+ if (pdata->slave[i].slave_id == param->slave_id)
return pdata->slave + i;
return NULL;
@@ -290,6 +289,7 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
struct sh_dmae_chan *sh_chan = to_sh_chan(chan);
struct sh_desc *desc;
struct sh_dmae_slave *param = chan->private;
+ int ret;
pm_runtime_get_sync(sh_chan->dev);
@@ -298,14 +298,18 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
* never runs concurrently with itself or free_chan_resources.
*/
if (param) {
- struct sh_dmae_slave_config *cfg;
+ const struct sh_dmae_slave_config *cfg;
- cfg = sh_dmae_find_slave(sh_chan, param->slave_id);
- if (!cfg)
- return -EINVAL;
+ cfg = sh_dmae_find_slave(sh_chan, param);
+ if (!cfg) {
+ ret = -EINVAL;
+ goto efindslave;
+ }
- if (test_and_set_bit(param->slave_id, sh_dmae_slave_used))
- return -EBUSY;
+ if (test_and_set_bit(param->slave_id, sh_dmae_slave_used)) {
+ ret = -EBUSY;
+ goto etestused;
+ }
param->config = cfg;
@@ -334,10 +338,20 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
}
spin_unlock_bh(&sh_chan->desc_lock);
- if (!sh_chan->descs_allocated)
- pm_runtime_put(sh_chan->dev);
+ if (!sh_chan->descs_allocated) {
+ ret = -ENOMEM;
+ goto edescalloc;
+ }
return sh_chan->descs_allocated;
+
+edescalloc:
+ if (param)
+ clear_bit(param->slave_id, sh_dmae_slave_used);
+etestused:
+efindslave:
+ pm_runtime_put(sh_chan->dev);
+ return ret;
}
/*
@@ -559,12 +573,14 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
{
struct sh_dmae_slave *param;
struct sh_dmae_chan *sh_chan;
+ dma_addr_t slave_addr;
if (!chan)
return NULL;
sh_chan = to_sh_chan(chan);
param = chan->private;
+ slave_addr = param->config->addr;
/* Someone calling slave DMA on a public channel? */
if (!param || !sg_len) {
@@ -577,7 +593,7 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_slave_sg(
* if (param != NULL), this is a successfully requested slave channel,
* therefore param->config != NULL too.
*/
- return sh_dmae_prep_sg(sh_chan, sgl, sg_len, &param->config->addr,
+ return sh_dmae_prep_sg(sh_chan, sgl, sg_len, &slave_addr,
direction, flags);
}
@@ -858,7 +874,7 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
int irq, unsigned long flags)
{
int err;
- struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id];
+ const struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id];
struct platform_device *pdev = to_platform_device(shdev->common.dev);
struct sh_dmae_chan *new_sh_chan;
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 153609a1e96c..4021275a0a43 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -17,8 +17,8 @@
#include <linux/interrupt.h>
#include <linux/list.h>
-#include <asm/dmaengine.h>
-
+#define SH_DMAC_MAX_CHANNELS 6
+#define SH_DMA_SLAVE_NUMBER 256
#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
struct device;
diff --git a/drivers/gpio/it8761e_gpio.c b/drivers/gpio/it8761e_gpio.c
index 753219cf993a..41a9388f2fde 100644
--- a/drivers/gpio/it8761e_gpio.c
+++ b/drivers/gpio/it8761e_gpio.c
@@ -80,8 +80,8 @@ static int it8761e_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
u16 reg;
u8 bit;
- bit = gpio_num % 7;
- reg = (gpio_num >= 7) ? gpio_ba + 1 : gpio_ba;
+ bit = gpio_num % 8;
+ reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
return !!(inb(reg) & (1 << bit));
}
@@ -91,8 +91,8 @@ static int it8761e_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
u8 curr_dirs;
u8 io_reg, bit;
- bit = gpio_num % 7;
- io_reg = (gpio_num >= 7) ? GPIO2X_IO : GPIO1X_IO;
+ bit = gpio_num % 8;
+ io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
spin_lock(&sio_lock);
@@ -116,8 +116,8 @@ static void it8761e_gpio_set(struct gpio_chip *gc,
u8 curr_vals, bit;
u16 reg;
- bit = gpio_num % 7;
- reg = (gpio_num >= 7) ? gpio_ba + 1 : gpio_ba;
+ bit = gpio_num % 8;
+ reg = (gpio_num >= 8) ? gpio_ba + 1 : gpio_ba;
spin_lock(&sio_lock);
@@ -135,8 +135,8 @@ static int it8761e_gpio_direction_out(struct gpio_chip *gc,
{
u8 curr_dirs, io_reg, bit;
- bit = gpio_num % 7;
- io_reg = (gpio_num >= 7) ? GPIO2X_IO : GPIO1X_IO;
+ bit = gpio_num % 8;
+ io_reg = (gpio_num >= 8) ? GPIO2X_IO : GPIO1X_IO;
it8761e_gpio_set(gc, gpio_num, val);
@@ -200,7 +200,7 @@ static int __init it8761e_gpio_init(void)
return -EBUSY;
it8761e_gpio_chip.base = -1;
- it8761e_gpio_chip.ngpio = 14;
+ it8761e_gpio_chip.ngpio = 16;
err = gpiochip_add(&it8761e_gpio_chip);
if (err < 0)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 2b8b969d0c15..df6a9cd82c4d 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -456,11 +456,15 @@ i915_error_object_create(struct drm_device *dev,
for (page = 0; page < page_count; page++) {
void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
+ unsigned long flags;
+
if (d == NULL)
goto unwind;
- s = kmap_atomic(src_priv->pages[page], KM_USER0);
+ local_irq_save(flags);
+ s = kmap_atomic(src_priv->pages[page], KM_IRQ0);
memcpy(d, s, PAGE_SIZE);
- kunmap_atomic(s, KM_USER0);
+ kunmap_atomic(s, KM_IRQ0);
+ local_irq_restore(flags);
dst->pages[page] = d;
}
dst->page_count = page_count;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 4b05563d99e1..b3749d47be7b 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -216,6 +216,7 @@ static struct drm_driver driver_old = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+ .read = drm_read,
#ifdef CONFIG_COMPAT
.compat_ioctl = radeon_compat_ioctl,
#endif
@@ -304,6 +305,7 @@ static struct drm_driver kms_driver = {
.mmap = radeon_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+ .read = drm_read,
#ifdef CONFIG_COMPAT
.compat_ioctl = radeon_kms_compat_ioctl,
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 40ab6d9c3736..cc5316dcf580 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -424,7 +424,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if ((*cmd & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
(*cmd & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
- offset = *cmd << 10;
+ offset = *cmd3 << 10;
if (radeon_check_and_fixup_offset
(dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid second packet offset\n");
@@ -2895,9 +2895,12 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
return rv;
rv = drm_buffer_copy_from_user(cmdbuf->buffer, buffer,
cmdbuf->bufsz);
- if (rv)
+ if (rv) {
+ drm_buffer_free(cmdbuf->buffer);
return rv;
- }
+ }
+ } else
+ goto done;
orig_nbox = cmdbuf->nbox;
@@ -2905,8 +2908,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
int temp;
temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
- if (cmdbuf->bufsz != 0)
- drm_buffer_free(cmdbuf->buffer);
+ drm_buffer_free(cmdbuf->buffer);
return temp;
}
@@ -3012,16 +3014,15 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
}
}
- if (cmdbuf->bufsz != 0)
- drm_buffer_free(cmdbuf->buffer);
+ drm_buffer_free(cmdbuf->buffer);
+ done:
DRM_DEBUG("DONE\n");
COMMIT_RING();
return 0;
err:
- if (cmdbuf->bufsz != 0)
- drm_buffer_free(cmdbuf->buffer);
+ drm_buffer_free(cmdbuf->buffer);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index dd47b2a9a791..0e3754a3a303 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1716,40 +1716,12 @@ int ttm_bo_wait(struct ttm_buffer_object *bo,
}
EXPORT_SYMBOL(ttm_bo_wait);
-void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo)
-{
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
-}
-
-int ttm_bo_block_reservation(struct ttm_buffer_object *bo, bool interruptible,
- bool no_wait)
-{
- int ret;
-
- while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
- if (no_wait)
- return -EBUSY;
- else if (interruptible) {
- ret = wait_event_interruptible
- (bo->event_queue, atomic_read(&bo->reserved) == 0);
- if (unlikely(ret != 0))
- return ret;
- } else {
- wait_event(bo->event_queue,
- atomic_read(&bo->reserved) == 0);
- }
- }
- return 0;
-}
-
int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
{
int ret = 0;
/*
- * Using ttm_bo_reserve instead of ttm_bo_block_reservation
- * makes sure the lru lists are updated.
+ * Using ttm_bo_reserve makes sure the lru lists are updated.
*/
ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c
index 3d172ef04ee1..de41e55a944a 100644
--- a/drivers/gpu/drm/ttm/ttm_lock.c
+++ b/drivers/gpu/drm/ttm/ttm_lock.c
@@ -204,7 +204,6 @@ static int __ttm_vt_unlock(struct ttm_lock *lock)
lock->flags &= ~TTM_VT_LOCK;
wake_up_all(&lock->queue);
spin_unlock(&lock->lock);
- printk(KERN_INFO TTM_PFX "vt unlock.\n");
return ret;
}
@@ -265,10 +264,8 @@ int ttm_vt_lock(struct ttm_lock *lock,
ttm_lock_type, &ttm_vt_lock_remove, NULL);
if (ret)
(void)__ttm_vt_unlock(lock);
- else {
+ else
lock->vt_holder = tfile;
- printk(KERN_INFO TTM_PFX "vt lock.\n");
- }
return ret;
}
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index 7e597d7f770f..24663a8717b1 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -59,6 +59,7 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static const struct hid_device_id ch_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ }
};
MODULE_DEVICE_TABLE(hid, ch_devices);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 2e2aa759d230..143e788b729b 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1043,13 +1043,8 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
- if (hid->claimed & HID_CLAIMED_HIDRAW) {
- /* numbered reports need to be passed with the report num */
- if (report_enum->numbered)
- hidraw_report_event(hid, data - 1, size + 1);
- else
- hidraw_report_event(hid, data, size);
- }
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ hidraw_report_event(hid, data, size);
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
@@ -1296,6 +1291,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 797e06470356..09d27649a0f7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -131,6 +131,7 @@
#define USB_VENDOR_ID_CHERRY 0x046a
#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
+#define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027
#define USB_VENDOR_ID_CHIC 0x05fe
#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 9b24fc510712..4777bbfa1cc2 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -1,8 +1,8 @@
/*
* HID driver for N-Trig touchscreens
*
- * Copyright (c) 2008 Rafi Rubin
- * Copyright (c) 2009 Stephane Chatty
+ * Copyright (c) 2008-2010 Rafi Rubin
+ * Copyright (c) 2009-2010 Stephane Chatty
*
*/
@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/hid.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
#include <linux/module.h>
#include <linux/slab.h>
@@ -22,17 +24,16 @@
#define NTRIG_DUPLICATE_USAGES 0x001
-#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
- EV_KEY, (c))
-
struct ntrig_data {
/* Incoming raw values for a single contact */
__u16 x, y, w, h;
__u16 id;
- __u8 confidence;
+
+ bool tipswitch;
+ bool confidence;
+ bool first_contact_touch;
bool reading_mt;
- __u8 first_contact_confidence;
__u8 mt_footer[4];
__u8 mt_foot_count;
@@ -139,9 +140,10 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
case 0xff000001:
/* Tag indicating the start of a multitouch group */
nd->reading_mt = 1;
- nd->first_contact_confidence = 0;
+ nd->first_contact_touch = 0;
break;
case HID_DG_TIPSWITCH:
+ nd->tipswitch = value;
/* Prevent emission of touch until validated */
return 1;
case HID_DG_CONFIDENCE:
@@ -169,8 +171,14 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
* to emit a normal (X, Y) position
*/
if (!nd->reading_mt) {
+ /*
+ * TipSwitch indicates the presence of a
+ * finger in single touch mode.
+ */
+ input_report_key(input, BTN_TOUCH,
+ nd->tipswitch);
input_report_key(input, BTN_TOOL_DOUBLETAP,
- (nd->confidence != 0));
+ nd->tipswitch);
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
}
@@ -209,7 +217,13 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
/* emit a normal (X, Y) for the first point only */
if (nd->id == 0) {
- nd->first_contact_confidence = nd->confidence;
+ /*
+ * TipSwitch is superfluous in multitouch
+ * mode. The footer events tell us
+ * if there is a finger on the screen or
+ * not.
+ */
+ nd->first_contact_touch = nd->confidence;
input_event(input, EV_ABS, ABS_X, nd->x);
input_event(input, EV_ABS, ABS_Y, nd->y);
}
@@ -239,30 +253,11 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
nd->reading_mt = 0;
- if (nd->first_contact_confidence) {
- switch (value) {
- case 0: /* for single touch devices */
- case 1:
- input_report_key(input,
- BTN_TOOL_DOUBLETAP, 1);
- break;
- case 2:
- input_report_key(input,
- BTN_TOOL_TRIPLETAP, 1);
- break;
- case 3:
- default:
- input_report_key(input,
- BTN_TOOL_QUADTAP, 1);
- }
+ if (nd->first_contact_touch) {
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
input_report_key(input, BTN_TOUCH, 1);
} else {
- input_report_key(input,
- BTN_TOOL_DOUBLETAP, 0);
- input_report_key(input,
- BTN_TOOL_TRIPLETAP, 0);
- input_report_key(input,
- BTN_TOOL_QUADTAP, 0);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
input_report_key(input, BTN_TOUCH, 0);
}
break;
@@ -286,6 +281,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct ntrig_data *nd;
struct hid_input *hidinput;
struct input_dev *input;
+ struct hid_report *report;
if (id->driver_data)
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
@@ -327,13 +323,7 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
__clear_bit(BTN_TOOL_PEN, input->keybit);
__clear_bit(BTN_TOOL_FINGER, input->keybit);
__clear_bit(BTN_0, input->keybit);
- /*
- * A little something special to enable
- * two and three finger taps.
- */
__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
- __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
- __set_bit(BTN_TOOL_QUADTAP, input->keybit);
/*
* The physical touchscreen (single touch)
* input has a value for physical, whereas
@@ -349,6 +339,12 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
+ /* This is needed for devices with more recent firmware versions */
+ report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
+ if (report)
+ usbhid_submit_report(hdev, report, USB_DIR_OUT);
+
+
return 0;
err_free:
kfree(nd);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 7502a4b2fa86..402d5574b574 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -76,7 +76,7 @@ static int sony_set_operational_usb(struct hid_device *hdev)
static int sony_set_operational_bt(struct hid_device *hdev)
{
- unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
+ unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
}
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index f7700cf49721..f947d8337e21 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -277,7 +277,6 @@ static int __init wacom_init(void)
ret = hid_register_driver(&wacom_driver);
if (ret)
printk(KERN_ERR "can't register wacom driver\n");
- printk(KERN_ERR "wacom driver registered\n");
return ret;
}
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 56d06cd8075b..7b85b696fdab 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -999,13 +999,6 @@ static int usbhid_start(struct hid_device *hid)
}
}
- init_waitqueue_head(&usbhid->wait);
- INIT_WORK(&usbhid->reset_work, hid_reset);
- INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
- setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
-
- spin_lock_init(&usbhid->lock);
-
usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
if (!usbhid->urbctrl) {
ret = -ENOMEM;
@@ -1179,6 +1172,12 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usbhid->intf = intf;
usbhid->ifnum = interface->desc.bInterfaceNumber;
+ init_waitqueue_head(&usbhid->wait);
+ INIT_WORK(&usbhid->reset_work, hid_reset);
+ INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
+ setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
+ spin_lock_init(&usbhid->lock);
+
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 0f28d91f29d8..f085c18d2905 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -195,6 +195,9 @@ static unsigned int applesmc_accelerometer;
/* Indicates whether this computer has light sensors and keyboard backlight. */
static unsigned int applesmc_light;
+/* The number of fans handled by the driver */
+static unsigned int fans_handled;
+
/* Indicates which temperature sensors set to use. */
static unsigned int applesmc_temperature_set;
@@ -1492,39 +1495,24 @@ static int __init applesmc_init(void)
/* create fan files */
count = applesmc_get_fan_count();
- if (count < 0) {
+ if (count < 0)
printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
- } else {
+ else
printk(KERN_INFO "applesmc: %d fans found.\n", count);
- switch (count) {
- default:
- printk(KERN_WARNING "applesmc: More than 4 fans found,"
- " but at most 4 fans are supported"
- " by the driver.\n");
- case 4:
- ret = sysfs_create_group(&pdev->dev.kobj,
- &fan_attribute_groups[3]);
- if (ret)
- goto out_key_enumeration;
- case 3:
- ret = sysfs_create_group(&pdev->dev.kobj,
- &fan_attribute_groups[2]);
- if (ret)
- goto out_key_enumeration;
- case 2:
- ret = sysfs_create_group(&pdev->dev.kobj,
- &fan_attribute_groups[1]);
- if (ret)
- goto out_key_enumeration;
- case 1:
- ret = sysfs_create_group(&pdev->dev.kobj,
- &fan_attribute_groups[0]);
- if (ret)
- goto out_fan_1;
- case 0:
- ;
- }
+ if (count > 4) {
+ count = 4;
+ printk(KERN_WARNING "applesmc: More than 4 fans found,"
+ " but at most 4 fans are supported"
+ " by the driver.\n");
+ }
+
+ while (fans_handled < count) {
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &fan_attribute_groups[fans_handled]);
+ if (ret)
+ goto out_fans;
+ fans_handled++;
}
for (i = 0;
@@ -1593,10 +1581,10 @@ out_accelerometer:
applesmc_release_accelerometer();
out_temperature:
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
- sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
-out_fan_1:
- sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
-out_key_enumeration:
+out_fans:
+ while (fans_handled)
+ sysfs_remove_group(&pdev->dev.kobj,
+ &fan_attribute_groups[--fans_handled]);
sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
out_name:
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
@@ -1622,8 +1610,9 @@ static void __exit applesmc_exit(void)
if (applesmc_accelerometer)
applesmc_release_accelerometer();
sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
- sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
- sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
+ while (fans_handled)
+ sysfs_remove_group(&pdev->dev.kobj,
+ &fan_attribute_groups[--fans_handled]);
sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_name.attr);
platform_device_unregister(pdev);
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index 7f948105d8ad..0f388adc6187 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -268,8 +268,11 @@ static ssize_t store_fan16(struct device *dev,
if (strict_strtol(buf, 10, &reqval))
return -EINVAL;
+ /* If a minimum RPM of zero is requested, then we set the register to
+ 0xffff. This value allows the fan to be stopped completely without
+ generating an alarm. */
reqval =
- (SENSORS_LIMIT((reqval) <= 0 ? 0 : 5400000 / (reqval), 0, 65534));
+ (reqval <= 0 ? 0xffff : SENSORS_LIMIT(5400000 / reqval, 0, 0xfffe));
mutex_lock(&data->update_lock);
data->reg[param->msb[0]] = (reqval >> 8) & 0xff;
@@ -285,8 +288,9 @@ static ssize_t store_fan16(struct device *dev,
* Voltages are scaled in the device so that the nominal voltage
* is 3/4ths of the 0-255 range (i.e. 192).
* If all voltages are 'normal' then all voltage registers will
- * read 0xC0. This doesn't help us if we don't have a point of refernce.
- * The data sheet however provides us with the full scale value for each
+ * read 0xC0.
+ *
+ * The data sheet provides us with the 3/4 scale value for each voltage
* which is stored in in_scaling. The sda->index parameter value provides
* the index into in_scaling.
*
@@ -295,7 +299,7 @@ static ssize_t store_fan16(struct device *dev,
*/
static int asc7621_in_scaling[] = {
- 3320, 3000, 4380, 6640, 16000
+ 2500, 2250, 3300, 5000, 12000
};
static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
@@ -306,19 +310,12 @@ static ssize_t show_in10(struct device *dev, struct device_attribute *attr,
u8 nr = sda->index;
mutex_lock(&data->update_lock);
- regval = (data->reg[param->msb[0]] * asc7621_in_scaling[nr]) / 256;
-
- /* The LSB value is a 2-bit scaling of the MSB's LSbit value.
- * I.E. If the maximim voltage for this input is 6640 millivolts then
- * a MSB register value of 0 = 0mv and 255 = 6640mv.
- * A 1 step change therefore represents 25.9mv (6640 / 256).
- * The extra 2-bits therefore represent increments of 6.48mv.
- */
- regval += ((asc7621_in_scaling[nr] / 256) / 4) *
- (data->reg[param->lsb[0]] >> 6);
-
+ regval = (data->reg[param->msb[0]] << 8) | (data->reg[param->lsb[0]]);
mutex_unlock(&data->update_lock);
+ /* The LSB value is a 2-bit scaling of the MSB's LSbit value. */
+ regval = (regval >> 6) * asc7621_in_scaling[nr] / (0xc0 << 2);
+
return sprintf(buf, "%u\n", regval);
}
@@ -331,7 +328,7 @@ static ssize_t show_in8(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n",
((data->reg[param->msb[0]] *
- asc7621_in_scaling[nr]) / 256));
+ asc7621_in_scaling[nr]) / 0xc0));
}
static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
@@ -344,9 +341,11 @@ static ssize_t store_in8(struct device *dev, struct device_attribute *attr,
if (strict_strtol(buf, 10, &reqval))
return -EINVAL;
- reqval = SENSORS_LIMIT(reqval, 0, asc7621_in_scaling[nr]);
+ reqval = SENSORS_LIMIT(reqval, 0, 0xffff);
+
+ reqval = reqval * 0xc0 / asc7621_in_scaling[nr];
- reqval = (reqval * 255 + 128) / asc7621_in_scaling[nr];
+ reqval = SENSORS_LIMIT(reqval, 0, 0xff);
mutex_lock(&data->update_lock);
data->reg[param->msb[0]] = reqval;
@@ -846,11 +845,11 @@ static struct asc7621_param asc7621_params[] = {
PWRITE(in3_max, 3, PRI_LOW, 0x4b, 0, 0, 0, in8),
PWRITE(in4_max, 4, PRI_LOW, 0x4d, 0, 0, 0, in8),
- PREAD(in0_alarm, 0, PRI_LOW, 0x41, 0, 0x01, 0, bitmask),
- PREAD(in1_alarm, 1, PRI_LOW, 0x41, 0, 0x01, 1, bitmask),
- PREAD(in2_alarm, 2, PRI_LOW, 0x41, 0, 0x01, 2, bitmask),
- PREAD(in3_alarm, 3, PRI_LOW, 0x41, 0, 0x01, 3, bitmask),
- PREAD(in4_alarm, 4, PRI_LOW, 0x42, 0, 0x01, 0, bitmask),
+ PREAD(in0_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 0, bitmask),
+ PREAD(in1_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 1, bitmask),
+ PREAD(in2_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 2, bitmask),
+ PREAD(in3_alarm, 3, PRI_HIGH, 0x41, 0, 0x01, 3, bitmask),
+ PREAD(in4_alarm, 4, PRI_HIGH, 0x42, 0, 0x01, 0, bitmask),
PREAD(fan1_input, 0, PRI_HIGH, 0x29, 0x28, 0, 0, fan16),
PREAD(fan2_input, 1, PRI_HIGH, 0x2b, 0x2a, 0, 0, fan16),
@@ -862,10 +861,10 @@ static struct asc7621_param asc7621_params[] = {
PWRITE(fan3_min, 2, PRI_LOW, 0x59, 0x58, 0, 0, fan16),
PWRITE(fan4_min, 3, PRI_LOW, 0x5b, 0x5a, 0, 0, fan16),
- PREAD(fan1_alarm, 0, PRI_LOW, 0x42, 0, 0x01, 0, bitmask),
- PREAD(fan2_alarm, 1, PRI_LOW, 0x42, 0, 0x01, 1, bitmask),
- PREAD(fan3_alarm, 2, PRI_LOW, 0x42, 0, 0x01, 2, bitmask),
- PREAD(fan4_alarm, 3, PRI_LOW, 0x42, 0, 0x01, 3, bitmask),
+ PREAD(fan1_alarm, 0, PRI_HIGH, 0x42, 0, 0x01, 2, bitmask),
+ PREAD(fan2_alarm, 1, PRI_HIGH, 0x42, 0, 0x01, 3, bitmask),
+ PREAD(fan3_alarm, 2, PRI_HIGH, 0x42, 0, 0x01, 4, bitmask),
+ PREAD(fan4_alarm, 3, PRI_HIGH, 0x42, 0, 0x01, 5, bitmask),
PREAD(temp1_input, 0, PRI_HIGH, 0x25, 0x10, 0, 0, temp10),
PREAD(temp2_input, 1, PRI_HIGH, 0x26, 0x15, 0, 0, temp10),
@@ -886,10 +885,10 @@ static struct asc7621_param asc7621_params[] = {
PWRITE(temp3_max, 2, PRI_LOW, 0x53, 0, 0, 0, temp8),
PWRITE(temp4_max, 3, PRI_LOW, 0x35, 0, 0, 0, temp8),
- PREAD(temp1_alarm, 0, PRI_LOW, 0x41, 0, 0x01, 4, bitmask),
- PREAD(temp2_alarm, 1, PRI_LOW, 0x41, 0, 0x01, 5, bitmask),
- PREAD(temp3_alarm, 2, PRI_LOW, 0x41, 0, 0x01, 6, bitmask),
- PREAD(temp4_alarm, 3, PRI_LOW, 0x43, 0, 0x01, 0, bitmask),
+ PREAD(temp1_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 4, bitmask),
+ PREAD(temp2_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 5, bitmask),
+ PREAD(temp3_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 6, bitmask),
+ PREAD(temp4_alarm, 3, PRI_HIGH, 0x43, 0, 0x01, 0, bitmask),
PWRITE(temp1_source, 0, PRI_LOW, 0x02, 0, 0x07, 4, bitmask),
PWRITE(temp2_source, 1, PRI_LOW, 0x02, 0, 0x07, 0, bitmask),
@@ -898,7 +897,7 @@ static struct asc7621_param asc7621_params[] = {
PWRITE(temp1_smoothing_enable, 0, PRI_LOW, 0x62, 0, 0x01, 3, bitmask),
PWRITE(temp2_smoothing_enable, 1, PRI_LOW, 0x63, 0, 0x01, 7, bitmask),
- PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x64, 0, 0x01, 3, bitmask),
+ PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x63, 0, 0x01, 3, bitmask),
PWRITE(temp4_smoothing_enable, 3, PRI_LOW, 0x3c, 0, 0x01, 3, bitmask),
PWRITE(temp1_smoothing_time, 0, PRI_LOW, 0x62, 0, 0x07, 0, temp_st),
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
index c8ab50516672..7580f55e67e3 100644
--- a/drivers/hwmon/hp_accel.c
+++ b/drivers/hwmon/hp_accel.c
@@ -328,8 +328,8 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
lis3lv02d_joystick_disable();
lis3lv02d_poweroff(&lis3_dev);
- flush_work(&hpled_led.work);
led_classdev_unregister(&hpled_led.led_classdev);
+ flush_work(&hpled_led.work);
return lis3lv02d_remove_fs(&lis3_dev);
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9c6170cd9aac..87ab0568bb0e 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -564,7 +564,7 @@ config I2C_STU300
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
- depends on ARCH_VERSATILE || ARCH_REALVIEW
+ depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index defce2877eef..b85450865ff0 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -409,7 +409,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
- PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
@@ -431,7 +431,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
- PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 7e18bcf05a66..46239e47a260 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -59,11 +59,11 @@ static unsigned int get_time_pit(void)
unsigned long flags;
unsigned int count;
- spin_lock_irqsave(&i8253_lock, flags);
+ raw_spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
- spin_unlock_irqrestore(&i8253_lock, flags);
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
return count;
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index c52bec4d0530..423e0e6031ab 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -929,6 +929,24 @@ static const struct input_device_id joydev_ids[] = {
.evbit = { BIT_MASK(EV_ABS) },
.absbit = { BIT_MASK(ABS_THROTTLE) },
},
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ .keybit = {[BIT_WORD(BTN_JOYSTICK)] = BIT_MASK(BTN_JOYSTICK) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(BTN_GAMEPAD)] = BIT_MASK(BTN_GAMEPAD) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(BTN_TRIGGER_HAPPY)] = BIT_MASK(BTN_TRIGGER_HAPPY) },
+ },
{ } /* Terminating entry */
};
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 1c0b529c06aa..4afe0a3b4884 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -146,11 +146,11 @@ static unsigned int get_time_pit(void)
unsigned long flags;
unsigned int count;
- spin_lock_irqsave(&i8253_lock, flags);
+ raw_spin_lock_irqsave(&i8253_lock, flags);
outb_p(0x00, 0x43);
count = inb_p(0x40);
count |= inb_p(0x40) << 8;
- spin_unlock_irqrestore(&i8253_lock, flags);
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
return count;
}
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index b1edd778639c..405febd94f24 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -54,6 +54,9 @@ static signed short btn_avb_wheel[] =
static signed short abs_joystick[] =
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short abs_joystick_rudder[] =
+{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, -1 };
+
static signed short abs_avb_pegasus[] =
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y,
ABS_HAT1X, ABS_HAT1Y, -1 };
@@ -76,8 +79,9 @@ static struct iforce_device iforce_device[] = {
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce },
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
+ { 0x06f8, 0x0001, "Guillemot Jet Leader Force Feedback", btn_joystick, abs_joystick_rudder, ff_iforce },
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
- { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
+ { 0x06f8, 0xa302, "Guillemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
{ 0x06d6, 0x29bc, "Trust Force Feedback Race Master", btn_wheel, abs_wheel, ff_iforce },
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index b41303d3ec54..6c96631ae5d9 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -212,6 +212,7 @@ static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
+ { USB_DEVICE(0x06f8, 0x0003) }, /* Guillemot Jet Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
{ USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
{ } /* Terminating entry */
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 64c102355f53..a8293388d019 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -143,19 +143,6 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
-config KEYBOARD_CORGI
- tristate "Corgi keyboard (deprecated)"
- depends on PXA_SHARPSL
- help
- Say Y here to enable the keyboard on the Sharp Zaurus SL-C7xx
- series of PDAs.
-
- This driver is now deprecated, use generic GPIO based matrix
- keyboard driver instead.
-
- To compile this driver as a module, choose M here: the
- module will be called corgikbd.
-
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
@@ -339,19 +326,6 @@ config KEYBOARD_PXA930_ROTARY
To compile this driver as a module, choose M here: the
module will be called pxa930_rotary.
-config KEYBOARD_SPITZ
- tristate "Spitz keyboard (deprecated)"
- depends on PXA_SHARPSL
- help
- Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000,
- SL-C3000 and Sl-C3100 series of PDAs.
-
- This driver is now deprecated, use generic GPIO based matrix
- keyboard driver instead.
-
- To compile this driver as a module, choose M here: the
- module will be called spitzkbd.
-
config KEYBOARD_STOWAWAY
tristate "Stowaway keyboard"
select SERIO
@@ -414,28 +388,6 @@ config KEYBOARD_TWL4030
To compile this driver as a module, choose M here: the
module will be called twl4030_keypad.
-config KEYBOARD_TOSA
- tristate "Tosa keyboard (deprecated)"
- depends on MACH_TOSA
- help
- Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
-
- This driver is now deprecated, use generic GPIO based matrix
- keyboard driver instead.
-
- To compile this driver as a module, choose M here: the
- module will be called tosakbd.
-
-config KEYBOARD_TOSA_USE_EXT_KEYCODES
- bool "Tosa keyboard: use extended keycodes"
- depends on KEYBOARD_TOSA
- help
- Say Y here to enable the tosa keyboard driver to generate extended
- (>= 127) keycodes. Be aware, that they can't be correctly interpreted
- by either console keyboard driver or by Kdrive keybd driver.
-
- Say Y only if you know, what you are doing!
-
config KEYBOARD_XTKBD
tristate "XT keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 706c6b5ed5f4..9a74127e4d17 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
-obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
@@ -33,10 +32,8 @@ obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
-obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
-obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
deleted file mode 100644
index 634af6a8e6b3..000000000000
--- a/drivers/input/keyboard/corgikbd.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Keyboard driver for Sharp Corgi models (SL-C7xx)
- *
- * Copyright (c) 2004-2005 Richard Purdie
- *
- * Based on xtkbd.c/locomkbd.c
- *
- * 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/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <mach/corgi.h>
-#include <mach/pxa2xx-gpio.h>
-#include <asm/hardware/scoop.h>
-
-#define KB_ROWS 8
-#define KB_COLS 12
-#define KB_ROWMASK(r) (1 << (r))
-#define SCANCODE(r,c) ( ((r)<<4) + (c) + 1 )
-/* zero code, 124 scancodes */
-#define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 )
-
-#define SCAN_INTERVAL (50) /* ms */
-#define HINGE_SCAN_INTERVAL (250) /* ms */
-
-#define CORGI_KEY_CALENDER KEY_F1
-#define CORGI_KEY_ADDRESS KEY_F2
-#define CORGI_KEY_FN KEY_F3
-#define CORGI_KEY_CANCEL KEY_F4
-#define CORGI_KEY_OFF KEY_SUSPEND
-#define CORGI_KEY_EXOK KEY_F5
-#define CORGI_KEY_EXCANCEL KEY_F6
-#define CORGI_KEY_EXJOGDOWN KEY_F7
-#define CORGI_KEY_EXJOGUP KEY_F8
-#define CORGI_KEY_JAP1 KEY_LEFTCTRL
-#define CORGI_KEY_JAP2 KEY_LEFTALT
-#define CORGI_KEY_MAIL KEY_F10
-#define CORGI_KEY_OK KEY_F11
-#define CORGI_KEY_MENU KEY_F12
-
-static unsigned char corgikbd_keycode[NR_SCANCODES] = {
- 0, /* 0 */
- 0, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, 0, 0, 0, 0, 0, 0, 0, /* 1-16 */
- 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, 0, 0, 0, 0, 0, 0, 0, /* 17-32 */
- KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
- CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
- CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */
- CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
- KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
- CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */
-};
-
-
-struct corgikbd {
- unsigned char keycode[ARRAY_SIZE(corgikbd_keycode)];
- struct input_dev *input;
-
- spinlock_t lock;
- struct timer_list timer;
- struct timer_list htimer;
-
- unsigned int suspended;
- unsigned long suspend_jiffies;
-};
-
-#define KB_DISCHARGE_DELAY 10
-#define KB_ACTIVATE_DELAY 10
-
-/* Helper functions for reading the keyboard matrix
- * Note: We should really be using the generic gpio functions to alter
- * GPDR but it requires a function call per GPIO bit which is
- * excessive when we need to access 12 bits at once, multiple times.
- * These functions must be called within local_irq_save()/local_irq_restore()
- * or similar.
- */
-static inline void corgikbd_discharge_all(void)
-{
- /* STROBE All HiZ */
- GPCR2 = CORGI_GPIO_ALL_STROBE_BIT;
- GPDR2 &= ~CORGI_GPIO_ALL_STROBE_BIT;
-}
-
-static inline void corgikbd_activate_all(void)
-{
- /* STROBE ALL -> High */
- GPSR2 = CORGI_GPIO_ALL_STROBE_BIT;
- GPDR2 |= CORGI_GPIO_ALL_STROBE_BIT;
-
- udelay(KB_DISCHARGE_DELAY);
-
- /* Clear any interrupts we may have triggered when altering the GPIO lines */
- GEDR1 = CORGI_GPIO_HIGH_SENSE_BIT;
- GEDR2 = CORGI_GPIO_LOW_SENSE_BIT;
-}
-
-static inline void corgikbd_activate_col(int col)
-{
- /* STROBE col -> High, not col -> HiZ */
- GPSR2 = CORGI_GPIO_STROBE_BIT(col);
- GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
-}
-
-static inline void corgikbd_reset_col(int col)
-{
- /* STROBE col -> Low */
- GPCR2 = CORGI_GPIO_STROBE_BIT(col);
- /* STROBE col -> out, not col -> HiZ */
- GPDR2 = (GPDR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(col);
-}
-
-#define GET_ROWS_STATUS(c) (((GPLR1 & CORGI_GPIO_HIGH_SENSE_BIT) >> CORGI_GPIO_HIGH_SENSE_RSHIFT) | ((GPLR2 & CORGI_GPIO_LOW_SENSE_BIT) << CORGI_GPIO_LOW_SENSE_LSHIFT))
-
-/*
- * The corgi keyboard only generates interrupts when a key is pressed.
- * When a key is pressed, we enable a timer which then scans the
- * keyboard to detect when the key is released.
- */
-
-/* Scan the hardware keyboard and push any changes up through the input layer */
-static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data)
-{
- unsigned int row, col, rowd;
- unsigned long flags;
- unsigned int num_pressed;
-
- if (corgikbd_data->suspended)
- return;
-
- spin_lock_irqsave(&corgikbd_data->lock, flags);
-
- num_pressed = 0;
- for (col = 0; col < KB_COLS; col++) {
- /*
- * Discharge the output driver capacitatance
- * in the keyboard matrix. (Yes it is significant..)
- */
-
- corgikbd_discharge_all();
- udelay(KB_DISCHARGE_DELAY);
-
- corgikbd_activate_col(col);
- udelay(KB_ACTIVATE_DELAY);
-
- rowd = GET_ROWS_STATUS(col);
- for (row = 0; row < KB_ROWS; row++) {
- unsigned int scancode, pressed;
-
- scancode = SCANCODE(row, col);
- pressed = rowd & KB_ROWMASK(row);
-
- input_report_key(corgikbd_data->input, corgikbd_data->keycode[scancode], pressed);
-
- if (pressed)
- num_pressed++;
-
- if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF)
- && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) {
- input_event(corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1);
- corgikbd_data->suspend_jiffies=jiffies;
- }
- }
- corgikbd_reset_col(col);
- }
-
- corgikbd_activate_all();
-
- input_sync(corgikbd_data->input);
-
- /* if any keys are pressed, enable the timer */
- if (num_pressed)
- mod_timer(&corgikbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL));
-
- spin_unlock_irqrestore(&corgikbd_data->lock, flags);
-}
-
-/*
- * corgi keyboard interrupt handler.
- */
-static irqreturn_t corgikbd_interrupt(int irq, void *dev_id)
-{
- struct corgikbd *corgikbd_data = dev_id;
-
- if (!timer_pending(&corgikbd_data->timer)) {
- /** wait chattering delay **/
- udelay(20);
- corgikbd_scankeyboard(corgikbd_data);
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * corgi timer checking for released keys
- */
-static void corgikbd_timer_callback(unsigned long data)
-{
- struct corgikbd *corgikbd_data = (struct corgikbd *) data;
- corgikbd_scankeyboard(corgikbd_data);
-}
-
-/*
- * The hinge switches generate no interrupt so they need to be
- * monitored by a timer.
- *
- * We debounce the switches and pass them to the input system.
- *
- * gprr == 0x00 - Keyboard with Landscape Screen
- * 0x08 - No Keyboard with Portrait Screen
- * 0x0c - Keyboard and Screen Closed
- */
-
-#define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x))
-#define HINGE_STABLE_COUNT 2
-static int sharpsl_hinge_state;
-static int hinge_count;
-
-static void corgikbd_hinge_timer(unsigned long data)
-{
- struct corgikbd *corgikbd_data = (struct corgikbd *) data;
- unsigned long gprr;
- unsigned long flags;
-
- gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB);
- gprr |= (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0);
- if (gprr != sharpsl_hinge_state) {
- hinge_count = 0;
- sharpsl_hinge_state = gprr;
- } else if (hinge_count < HINGE_STABLE_COUNT) {
- hinge_count++;
- if (hinge_count >= HINGE_STABLE_COUNT) {
- spin_lock_irqsave(&corgikbd_data->lock, flags);
-
- input_report_switch(corgikbd_data->input, SW_LID, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0));
- input_report_switch(corgikbd_data->input, SW_TABLET_MODE, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0));
- input_report_switch(corgikbd_data->input, SW_HEADPHONE_INSERT, (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0));
- input_sync(corgikbd_data->input);
-
- spin_unlock_irqrestore(&corgikbd_data->lock, flags);
- }
- }
- mod_timer(&corgikbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
-}
-
-#ifdef CONFIG_PM
-static int corgikbd_suspend(struct platform_device *dev, pm_message_t state)
-{
- int i;
- struct corgikbd *corgikbd = platform_get_drvdata(dev);
-
- corgikbd->suspended = 1;
- /* strobe 0 is the power key so this can't be made an input for
- powersaving therefore i = 1 */
- for (i = 1; i < CORGI_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_IN);
-
- return 0;
-}
-
-static int corgikbd_resume(struct platform_device *dev)
-{
- int i;
- struct corgikbd *corgikbd = platform_get_drvdata(dev);
-
- for (i = 1; i < CORGI_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
-
- /* Upon resume, ignore the suspend key for a short while */
- corgikbd->suspend_jiffies=jiffies;
- corgikbd->suspended = 0;
-
- return 0;
-}
-#else
-#define corgikbd_suspend NULL
-#define corgikbd_resume NULL
-#endif
-
-static int __devinit corgikbd_probe(struct platform_device *pdev)
-{
- struct corgikbd *corgikbd;
- struct input_dev *input_dev;
- int i, err = -ENOMEM;
-
- corgikbd = kzalloc(sizeof(struct corgikbd), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!corgikbd || !input_dev)
- goto fail;
-
- platform_set_drvdata(pdev, corgikbd);
-
- corgikbd->input = input_dev;
- spin_lock_init(&corgikbd->lock);
-
- /* Init Keyboard rescan timer */
- init_timer(&corgikbd->timer);
- corgikbd->timer.function = corgikbd_timer_callback;
- corgikbd->timer.data = (unsigned long) corgikbd;
-
- /* Init Hinge Timer */
- init_timer(&corgikbd->htimer);
- corgikbd->htimer.function = corgikbd_hinge_timer;
- corgikbd->htimer.data = (unsigned long) corgikbd;
-
- corgikbd->suspend_jiffies=jiffies;
-
- memcpy(corgikbd->keycode, corgikbd_keycode, sizeof(corgikbd->keycode));
-
- input_dev->name = "Corgi Keyboard";
- input_dev->phys = "corgikbd/input0";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &pdev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
- BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
- input_dev->keycode = corgikbd->keycode;
- input_dev->keycodesize = sizeof(unsigned char);
- input_dev->keycodemax = ARRAY_SIZE(corgikbd_keycode);
-
- for (i = 0; i < ARRAY_SIZE(corgikbd_keycode); i++)
- set_bit(corgikbd->keycode[i], input_dev->keybit);
- clear_bit(0, input_dev->keybit);
- set_bit(SW_LID, input_dev->swbit);
- set_bit(SW_TABLET_MODE, input_dev->swbit);
- set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
-
- err = input_register_device(corgikbd->input);
- if (err)
- goto fail;
-
- mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
-
- /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
- for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
- pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN);
- if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "corgikbd", corgikbd))
- printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i);
- }
-
- /* Set Strobe lines as outputs - set high */
- for (i = 0; i < CORGI_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH);
-
- /* Setup the headphone jack as an input */
- pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN);
-
- return 0;
-
- fail: input_free_device(input_dev);
- kfree(corgikbd);
- return err;
-}
-
-static int __devexit corgikbd_remove(struct platform_device *pdev)
-{
- int i;
- struct corgikbd *corgikbd = platform_get_drvdata(pdev);
-
- for (i = 0; i < CORGI_KEY_SENSE_NUM; i++)
- free_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd);
-
- del_timer_sync(&corgikbd->htimer);
- del_timer_sync(&corgikbd->timer);
-
- input_unregister_device(corgikbd->input);
-
- kfree(corgikbd);
-
- return 0;
-}
-
-static struct platform_driver corgikbd_driver = {
- .probe = corgikbd_probe,
- .remove = __devexit_p(corgikbd_remove),
- .suspend = corgikbd_suspend,
- .resume = corgikbd_resume,
- .driver = {
- .name = "corgi-keyboard",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init corgikbd_init(void)
-{
- return platform_driver_register(&corgikbd_driver);
-}
-
-static void __exit corgikbd_exit(void)
-{
- platform_driver_unregister(&corgikbd_driver);
-}
-
-module_init(corgikbd_init);
-module_exit(corgikbd_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-MODULE_DESCRIPTION("Corgi Keyboard Driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:corgi-keyboard");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
deleted file mode 100644
index 13967422658c..000000000000
--- a/drivers/input/keyboard/spitzkbd.c
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series)
- *
- * Copyright (c) 2005 Richard Purdie
- *
- * Based on corgikbd.c
- *
- * 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/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <mach/spitz.h>
-#include <mach/pxa2xx-gpio.h>
-
-#define KB_ROWS 7
-#define KB_COLS 11
-#define KB_ROWMASK(r) (1 << (r))
-#define SCANCODE(r,c) (((r)<<4) + (c) + 1)
-#define NR_SCANCODES ((KB_ROWS<<4) + 1)
-
-#define SCAN_INTERVAL (50) /* ms */
-#define HINGE_SCAN_INTERVAL (150) /* ms */
-
-#define SPITZ_KEY_CALENDER KEY_F1
-#define SPITZ_KEY_ADDRESS KEY_F2
-#define SPITZ_KEY_FN KEY_F3
-#define SPITZ_KEY_CANCEL KEY_F4
-#define SPITZ_KEY_EXOK KEY_F5
-#define SPITZ_KEY_EXCANCEL KEY_F6
-#define SPITZ_KEY_EXJOGDOWN KEY_F7
-#define SPITZ_KEY_EXJOGUP KEY_F8
-#define SPITZ_KEY_JAP1 KEY_LEFTALT
-#define SPITZ_KEY_JAP2 KEY_RIGHTCTRL
-#define SPITZ_KEY_SYNC KEY_F9
-#define SPITZ_KEY_MAIL KEY_F10
-#define SPITZ_KEY_OK KEY_F11
-#define SPITZ_KEY_MENU KEY_F12
-
-static unsigned char spitzkbd_keycode[NR_SCANCODES] = {
- 0, /* 0 */
- KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */
- 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */
- KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
- SPITZ_KEY_ADDRESS, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
- SPITZ_KEY_CALENDER, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */
- SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */
- KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */
-};
-
-static int spitz_strobes[] = {
- SPITZ_GPIO_KEY_STROBE0,
- SPITZ_GPIO_KEY_STROBE1,
- SPITZ_GPIO_KEY_STROBE2,
- SPITZ_GPIO_KEY_STROBE3,
- SPITZ_GPIO_KEY_STROBE4,
- SPITZ_GPIO_KEY_STROBE5,
- SPITZ_GPIO_KEY_STROBE6,
- SPITZ_GPIO_KEY_STROBE7,
- SPITZ_GPIO_KEY_STROBE8,
- SPITZ_GPIO_KEY_STROBE9,
- SPITZ_GPIO_KEY_STROBE10,
-};
-
-static int spitz_senses[] = {
- SPITZ_GPIO_KEY_SENSE0,
- SPITZ_GPIO_KEY_SENSE1,
- SPITZ_GPIO_KEY_SENSE2,
- SPITZ_GPIO_KEY_SENSE3,
- SPITZ_GPIO_KEY_SENSE4,
- SPITZ_GPIO_KEY_SENSE5,
- SPITZ_GPIO_KEY_SENSE6,
-};
-
-struct spitzkbd {
- unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)];
- struct input_dev *input;
- char phys[32];
-
- spinlock_t lock;
- struct timer_list timer;
- struct timer_list htimer;
-
- unsigned int suspended;
- unsigned long suspend_jiffies;
-};
-
-#define KB_DISCHARGE_DELAY 10
-#define KB_ACTIVATE_DELAY 10
-
-/* Helper functions for reading the keyboard matrix
- * Note: We should really be using the generic gpio functions to alter
- * GPDR but it requires a function call per GPIO bit which is
- * excessive when we need to access 11 bits at once, multiple times.
- * These functions must be called within local_irq_save()/local_irq_restore()
- * or similar.
- */
-static inline void spitzkbd_discharge_all(void)
-{
- /* STROBE All HiZ */
- GPCR0 = SPITZ_GPIO_G0_STROBE_BIT;
- GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
- GPCR1 = SPITZ_GPIO_G1_STROBE_BIT;
- GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
- GPCR2 = SPITZ_GPIO_G2_STROBE_BIT;
- GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
- GPCR3 = SPITZ_GPIO_G3_STROBE_BIT;
- GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
-}
-
-static inline void spitzkbd_activate_all(void)
-{
- /* STROBE ALL -> High */
- GPSR0 = SPITZ_GPIO_G0_STROBE_BIT;
- GPDR0 |= SPITZ_GPIO_G0_STROBE_BIT;
- GPSR1 = SPITZ_GPIO_G1_STROBE_BIT;
- GPDR1 |= SPITZ_GPIO_G1_STROBE_BIT;
- GPSR2 = SPITZ_GPIO_G2_STROBE_BIT;
- GPDR2 |= SPITZ_GPIO_G2_STROBE_BIT;
- GPSR3 = SPITZ_GPIO_G3_STROBE_BIT;
- GPDR3 |= SPITZ_GPIO_G3_STROBE_BIT;
-
- udelay(KB_DISCHARGE_DELAY);
-
- /* Clear any interrupts we may have triggered when altering the GPIO lines */
- GEDR0 = SPITZ_GPIO_G0_SENSE_BIT;
- GEDR1 = SPITZ_GPIO_G1_SENSE_BIT;
- GEDR2 = SPITZ_GPIO_G2_SENSE_BIT;
- GEDR3 = SPITZ_GPIO_G3_SENSE_BIT;
-}
-
-static inline void spitzkbd_activate_col(int col)
-{
- int gpio = spitz_strobes[col];
- GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
- GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
- GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
- GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
- GPSR(gpio) = GPIO_bit(gpio);
- GPDR(gpio) |= GPIO_bit(gpio);
-}
-
-static inline void spitzkbd_reset_col(int col)
-{
- int gpio = spitz_strobes[col];
- GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
- GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
- GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
- GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
- GPCR(gpio) = GPIO_bit(gpio);
- GPDR(gpio) |= GPIO_bit(gpio);
-}
-
-static inline int spitzkbd_get_row_status(int col)
-{
- return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02)
- | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08)
- | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60);
-}
-
-/*
- * The spitz keyboard only generates interrupts when a key is pressed.
- * When a key is pressed, we enable a timer which then scans the
- * keyboard to detect when the key is released.
- */
-
-/* Scan the hardware keyboard and push any changes up through the input layer */
-static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data)
-{
- unsigned int row, col, rowd;
- unsigned long flags;
- unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0);
-
- if (spitzkbd_data->suspended)
- return;
-
- spin_lock_irqsave(&spitzkbd_data->lock, flags);
-
- num_pressed = 0;
- for (col = 0; col < KB_COLS; col++) {
- /*
- * Discharge the output driver capacitatance
- * in the keyboard matrix. (Yes it is significant..)
- */
-
- spitzkbd_discharge_all();
- udelay(KB_DISCHARGE_DELAY);
-
- spitzkbd_activate_col(col);
- udelay(KB_ACTIVATE_DELAY);
-
- rowd = spitzkbd_get_row_status(col);
- for (row = 0; row < KB_ROWS; row++) {
- unsigned int scancode, pressed;
-
- scancode = SCANCODE(row, col);
- pressed = rowd & KB_ROWMASK(row);
-
- input_report_key(spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed);
-
- if (pressed)
- num_pressed++;
- }
- spitzkbd_reset_col(col);
- }
-
- spitzkbd_activate_all();
-
- input_report_key(spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 );
- input_report_key(spitzkbd_data->input, KEY_SUSPEND, pwrkey);
-
- if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) {
- input_event(spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1);
- spitzkbd_data->suspend_jiffies = jiffies;
- }
-
- input_sync(spitzkbd_data->input);
-
- /* if any keys are pressed, enable the timer */
- if (num_pressed)
- mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL));
-
- spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
-}
-
-/*
- * spitz keyboard interrupt handler.
- */
-static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id)
-{
- struct spitzkbd *spitzkbd_data = dev_id;
-
- if (!timer_pending(&spitzkbd_data->timer)) {
- /** wait chattering delay **/
- udelay(20);
- spitzkbd_scankeyboard(spitzkbd_data);
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * spitz timer checking for released keys
- */
-static void spitzkbd_timer_callback(unsigned long data)
-{
- struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
-
- spitzkbd_scankeyboard(spitzkbd_data);
-}
-
-/*
- * The hinge switches generate an interrupt.
- * We debounce the switches and pass them to the input system.
- */
-
-static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id)
-{
- struct spitzkbd *spitzkbd_data = dev_id;
-
- if (!timer_pending(&spitzkbd_data->htimer))
- mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
-
- return IRQ_HANDLED;
-}
-
-#define HINGE_STABLE_COUNT 2
-static int sharpsl_hinge_state;
-static int hinge_count;
-
-static void spitzkbd_hinge_timer(unsigned long data)
-{
- struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
- unsigned long state;
- unsigned long flags;
-
- state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB));
- state |= (GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT));
- if (state != sharpsl_hinge_state) {
- hinge_count = 0;
- sharpsl_hinge_state = state;
- } else if (hinge_count < HINGE_STABLE_COUNT) {
- hinge_count++;
- }
-
- if (hinge_count >= HINGE_STABLE_COUNT) {
- spin_lock_irqsave(&spitzkbd_data->lock, flags);
-
- input_report_switch(spitzkbd_data->input, SW_LID, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0));
- input_report_switch(spitzkbd_data->input, SW_TABLET_MODE, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0));
- input_report_switch(spitzkbd_data->input, SW_HEADPHONE_INSERT, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0));
- input_sync(spitzkbd_data->input);
-
- spin_unlock_irqrestore(&spitzkbd_data->lock, flags);
- } else {
- mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
- }
-}
-
-#ifdef CONFIG_PM
-static int spitzkbd_suspend(struct platform_device *dev, pm_message_t state)
-{
- int i;
- struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
- spitzkbd->suspended = 1;
-
- /* Set Strobe lines as inputs - *except* strobe line 0 leave this
- enabled so we can detect a power button press for resume */
- for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(spitz_strobes[i] | GPIO_IN);
-
- return 0;
-}
-
-static int spitzkbd_resume(struct platform_device *dev)
-{
- int i;
- struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
-
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
-
- /* Upon resume, ignore the suspend key for a short while */
- spitzkbd->suspend_jiffies = jiffies;
- spitzkbd->suspended = 0;
-
- return 0;
-}
-#else
-#define spitzkbd_suspend NULL
-#define spitzkbd_resume NULL
-#endif
-
-static int __devinit spitzkbd_probe(struct platform_device *dev)
-{
- struct spitzkbd *spitzkbd;
- struct input_dev *input_dev;
- int i, err = -ENOMEM;
-
- spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!spitzkbd || !input_dev)
- goto fail;
-
- platform_set_drvdata(dev, spitzkbd);
- strcpy(spitzkbd->phys, "spitzkbd/input0");
-
- spin_lock_init(&spitzkbd->lock);
-
- /* Init Keyboard rescan timer */
- init_timer(&spitzkbd->timer);
- spitzkbd->timer.function = spitzkbd_timer_callback;
- spitzkbd->timer.data = (unsigned long) spitzkbd;
-
- /* Init Hinge Timer */
- init_timer(&spitzkbd->htimer);
- spitzkbd->htimer.function = spitzkbd_hinge_timer;
- spitzkbd->htimer.data = (unsigned long) spitzkbd;
-
- spitzkbd->suspend_jiffies = jiffies;
-
- spitzkbd->input = input_dev;
-
- input_dev->name = "Spitz Keyboard";
- input_dev->phys = spitzkbd->phys;
- input_dev->dev.parent = &dev->dev;
-
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
- BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
- input_dev->keycode = spitzkbd->keycode;
- input_dev->keycodesize = sizeof(unsigned char);
- input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode);
-
- memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode));
- for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++)
- set_bit(spitzkbd->keycode[i], input_dev->keybit);
- clear_bit(0, input_dev->keybit);
- set_bit(KEY_SUSPEND, input_dev->keybit);
- set_bit(SW_LID, input_dev->swbit);
- set_bit(SW_TABLET_MODE, input_dev->swbit);
- set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
-
- err = input_register_device(input_dev);
- if (err)
- goto fail;
-
- mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
-
- /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) {
- pxa_gpio_mode(spitz_senses[i] | GPIO_IN);
- if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt,
- IRQF_DISABLED|IRQF_TRIGGER_RISING,
- "Spitzkbd Sense", spitzkbd))
- printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i);
- }
-
- /* Set Strobe lines as outputs - set high */
- for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
- pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
-
- pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
- pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN);
- pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN);
- pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN);
-
- request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Spitzkbd Sync", spitzkbd);
- request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Spitzkbd PwrOn", spitzkbd);
- request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Spitzkbd SWA", spitzkbd);
- request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Spitzkbd SWB", spitzkbd);
- request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
- IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "Spitzkbd HP", spitzkbd);
-
- return 0;
-
- fail: input_free_device(input_dev);
- kfree(spitzkbd);
- return err;
-}
-
-static int __devexit spitzkbd_remove(struct platform_device *dev)
-{
- int i;
- struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
-
- for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++)
- free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd);
-
- free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd);
- free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd);
- free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd);
- free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd);
- free_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd);
-
- del_timer_sync(&spitzkbd->htimer);
- del_timer_sync(&spitzkbd->timer);
-
- input_unregister_device(spitzkbd->input);
-
- kfree(spitzkbd);
-
- return 0;
-}
-
-static struct platform_driver spitzkbd_driver = {
- .probe = spitzkbd_probe,
- .remove = __devexit_p(spitzkbd_remove),
- .suspend = spitzkbd_suspend,
- .resume = spitzkbd_resume,
- .driver = {
- .name = "spitz-keyboard",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init spitzkbd_init(void)
-{
- return platform_driver_register(&spitzkbd_driver);
-}
-
-static void __exit spitzkbd_exit(void)
-{
- platform_driver_unregister(&spitzkbd_driver);
-}
-
-module_init(spitzkbd_init);
-module_exit(spitzkbd_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-MODULE_DESCRIPTION("Spitz Keyboard Driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:spitz-keyboard");
diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c
deleted file mode 100644
index 3910f269cfc8..000000000000
--- a/drivers/input/keyboard/tosakbd.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Keyboard driver for Sharp Tosa models (SL-6000x)
- *
- * Copyright (c) 2005 Dirk Opfer
- * Copyright (c) 2007 Dmitry Baryshkov
- *
- * Based on xtkbd.c/locomkbd.c/corgikbd.c
- *
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-
-#include <mach/gpio.h>
-#include <mach/tosa.h>
-
-#define KB_ROWMASK(r) (1 << (r))
-#define SCANCODE(r, c) (((r)<<4) + (c) + 1)
-#define NR_SCANCODES SCANCODE(TOSA_KEY_SENSE_NUM - 1, TOSA_KEY_STROBE_NUM - 1) + 1
-
-#define SCAN_INTERVAL (HZ/10)
-
-#define KB_DISCHARGE_DELAY 10
-#define KB_ACTIVATE_DELAY 10
-
-static unsigned short tosakbd_keycode[NR_SCANCODES] = {
-0,
-0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
-0, 0, 0, 0, 0, 0, 0, 0,
-KEY_Q, KEY_E, KEY_T, KEY_Y, 0, KEY_O, KEY_I, KEY_COMMA,
-0, 0, 0, 0, 0, 0, 0, 0,
-KEY_A, KEY_D, KEY_G, KEY_U, 0, KEY_L, KEY_ENTER, KEY_DOT,
-0, 0, 0, 0, 0, 0, 0, 0,
-KEY_Z, KEY_C, KEY_V, KEY_J, TOSA_KEY_ADDRESSBOOK, TOSA_KEY_CANCEL, TOSA_KEY_CENTER, TOSA_KEY_OK,
-KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, 0,
-KEY_S, KEY_R, KEY_B, KEY_N, TOSA_KEY_CALENDAR, TOSA_KEY_HOMEPAGE, KEY_LEFTCTRL, TOSA_KEY_LIGHT,
-0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,
-KEY_TAB, KEY_SLASH, KEY_H, KEY_M, TOSA_KEY_MENU, 0, KEY_UP, 0,
-0, 0, TOSA_KEY_FN, 0, 0, 0, 0, 0,
-KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_RIGHT,
-0, 0, 0,
-};
-
-struct tosakbd {
- unsigned short keycode[ARRAY_SIZE(tosakbd_keycode)];
- struct input_dev *input;
- bool suspended;
- spinlock_t lock; /* protect kbd scanning */
- struct timer_list timer;
-};
-
-
-/* Helper functions for reading the keyboard matrix
- * Note: We should really be using the generic gpio functions to alter
- * GPDR but it requires a function call per GPIO bit which is
- * excessive when we need to access 12 bits at once, multiple times.
- * These functions must be called within local_irq_save()/local_irq_restore()
- * or similar.
- */
-#define GET_ROWS_STATUS(c) ((GPLR2 & TOSA_GPIO_ALL_SENSE_BIT) >> TOSA_GPIO_ALL_SENSE_RSHIFT)
-
-static inline void tosakbd_discharge_all(void)
-{
- /* STROBE All HiZ */
- GPCR1 = TOSA_GPIO_HIGH_STROBE_BIT;
- GPDR1 &= ~TOSA_GPIO_HIGH_STROBE_BIT;
- GPCR2 = TOSA_GPIO_LOW_STROBE_BIT;
- GPDR2 &= ~TOSA_GPIO_LOW_STROBE_BIT;
-}
-
-static inline void tosakbd_activate_all(void)
-{
- /* STROBE ALL -> High */
- GPSR1 = TOSA_GPIO_HIGH_STROBE_BIT;
- GPDR1 |= TOSA_GPIO_HIGH_STROBE_BIT;
- GPSR2 = TOSA_GPIO_LOW_STROBE_BIT;
- GPDR2 |= TOSA_GPIO_LOW_STROBE_BIT;
-
- udelay(KB_DISCHARGE_DELAY);
-
- /* STATE CLEAR */
- GEDR2 |= TOSA_GPIO_ALL_SENSE_BIT;
-}
-
-static inline void tosakbd_activate_col(int col)
-{
- if (col <= 5) {
- /* STROBE col -> High, not col -> HiZ */
- GPSR1 = TOSA_GPIO_STROBE_BIT(col);
- GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
- } else {
- /* STROBE col -> High, not col -> HiZ */
- GPSR2 = TOSA_GPIO_STROBE_BIT(col);
- GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
- }
-}
-
-static inline void tosakbd_reset_col(int col)
-{
- if (col <= 5) {
- /* STROBE col -> Low */
- GPCR1 = TOSA_GPIO_STROBE_BIT(col);
- /* STROBE col -> out, not col -> HiZ */
- GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
- } else {
- /* STROBE col -> Low */
- GPCR2 = TOSA_GPIO_STROBE_BIT(col);
- /* STROBE col -> out, not col -> HiZ */
- GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
- }
-}
-/*
- * The tosa keyboard only generates interrupts when a key is pressed.
- * So when a key is pressed, we enable a timer. This timer scans the
- * keyboard, and this is how we detect when the key is released.
- */
-
-/* Scan the hardware keyboard and push any changes up through the input layer */
-static void tosakbd_scankeyboard(struct platform_device *dev)
-{
- struct tosakbd *tosakbd = platform_get_drvdata(dev);
- unsigned int row, col, rowd;
- unsigned long flags;
- unsigned int num_pressed = 0;
-
- spin_lock_irqsave(&tosakbd->lock, flags);
-
- if (tosakbd->suspended)
- goto out;
-
- for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) {
- /*
- * Discharge the output driver capacitatance
- * in the keyboard matrix. (Yes it is significant..)
- */
- tosakbd_discharge_all();
- udelay(KB_DISCHARGE_DELAY);
-
- tosakbd_activate_col(col);
- udelay(KB_ACTIVATE_DELAY);
-
- rowd = GET_ROWS_STATUS(col);
-
- for (row = 0; row < TOSA_KEY_SENSE_NUM; row++) {
- unsigned int scancode, pressed;
- scancode = SCANCODE(row, col);
- pressed = rowd & KB_ROWMASK(row);
-
- if (pressed && !tosakbd->keycode[scancode])
- dev_warn(&dev->dev,
- "unhandled scancode: 0x%02x\n",
- scancode);
-
- input_report_key(tosakbd->input,
- tosakbd->keycode[scancode],
- pressed);
- if (pressed)
- num_pressed++;
- }
-
- tosakbd_reset_col(col);
- }
-
- tosakbd_activate_all();
-
- input_sync(tosakbd->input);
-
- /* if any keys are pressed, enable the timer */
- if (num_pressed)
- mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL);
-
- out:
- spin_unlock_irqrestore(&tosakbd->lock, flags);
-}
-
-/*
- * tosa keyboard interrupt handler.
- */
-static irqreturn_t tosakbd_interrupt(int irq, void *__dev)
-{
- struct platform_device *dev = __dev;
- struct tosakbd *tosakbd = platform_get_drvdata(dev);
-
- if (!timer_pending(&tosakbd->timer)) {
- /** wait chattering delay **/
- udelay(20);
- tosakbd_scankeyboard(dev);
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * tosa timer checking for released keys
- */
-static void tosakbd_timer_callback(unsigned long __dev)
-{
- struct platform_device *dev = (struct platform_device *)__dev;
-
- tosakbd_scankeyboard(dev);
-}
-
-#ifdef CONFIG_PM
-static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct tosakbd *tosakbd = platform_get_drvdata(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&tosakbd->lock, flags);
- tosakbd->suspended = true;
- spin_unlock_irqrestore(&tosakbd->lock, flags);
-
- del_timer_sync(&tosakbd->timer);
-
- return 0;
-}
-
-static int tosakbd_resume(struct platform_device *dev)
-{
- struct tosakbd *tosakbd = platform_get_drvdata(dev);
-
- tosakbd->suspended = false;
- tosakbd_scankeyboard(dev);
-
- return 0;
-}
-#else
-#define tosakbd_suspend NULL
-#define tosakbd_resume NULL
-#endif
-
-static int __devinit tosakbd_probe(struct platform_device *pdev) {
-
- int i;
- struct tosakbd *tosakbd;
- struct input_dev *input_dev;
- int error;
-
- tosakbd = kzalloc(sizeof(struct tosakbd), GFP_KERNEL);
- if (!tosakbd)
- return -ENOMEM;
-
- input_dev = input_allocate_device();
- if (!input_dev) {
- kfree(tosakbd);
- return -ENOMEM;
- }
-
- platform_set_drvdata(pdev, tosakbd);
-
- spin_lock_init(&tosakbd->lock);
-
- /* Init Keyboard rescan timer */
- init_timer(&tosakbd->timer);
- tosakbd->timer.function = tosakbd_timer_callback;
- tosakbd->timer.data = (unsigned long) pdev;
-
- tosakbd->input = input_dev;
-
- input_set_drvdata(input_dev, tosakbd);
- input_dev->name = "Tosa Keyboard";
- input_dev->phys = "tosakbd/input0";
- input_dev->dev.parent = &pdev->dev;
-
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
-
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- input_dev->keycode = tosakbd->keycode;
- input_dev->keycodesize = sizeof(tosakbd->keycode[0]);
- input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
-
- memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
-
- for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
- __set_bit(tosakbd->keycode[i], input_dev->keybit);
- __clear_bit(KEY_RESERVED, input_dev->keybit);
-
- /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
- for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
- int gpio = TOSA_GPIO_KEY_SENSE(i);
- int irq;
- error = gpio_request(gpio, "tosakbd");
- if (error < 0) {
- printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
- " error %d\n", gpio, error);
- goto fail;
- }
-
- error = gpio_direction_input(TOSA_GPIO_KEY_SENSE(i));
- if (error < 0) {
- printk(KERN_ERR "tosakbd: failed to configure input"
- " direction for GPIO %d, error %d\n",
- gpio, error);
- gpio_free(gpio);
- goto fail;
- }
-
- irq = gpio_to_irq(gpio);
- if (irq < 0) {
- error = irq;
- printk(KERN_ERR "gpio-keys: Unable to get irq number"
- " for GPIO %d, error %d\n",
- gpio, error);
- gpio_free(gpio);
- goto fail;
- }
-
- error = request_irq(irq, tosakbd_interrupt,
- IRQF_DISABLED | IRQF_TRIGGER_RISING,
- "tosakbd", pdev);
-
- if (error) {
- printk("tosakbd: Can't get IRQ: %d: error %d!\n",
- irq, error);
- gpio_free(gpio);
- goto fail;
- }
- }
-
- /* Set Strobe lines as outputs - set high */
- for (i = 0; i < TOSA_KEY_STROBE_NUM; i++) {
- int gpio = TOSA_GPIO_KEY_STROBE(i);
- error = gpio_request(gpio, "tosakbd");
- if (error < 0) {
- printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
- " error %d\n", gpio, error);
- goto fail2;
- }
-
- error = gpio_direction_output(gpio, 1);
- if (error < 0) {
- printk(KERN_ERR "tosakbd: failed to configure input"
- " direction for GPIO %d, error %d\n",
- gpio, error);
- gpio_free(gpio);
- goto fail2;
- }
-
- }
-
- error = input_register_device(input_dev);
- if (error) {
- printk(KERN_ERR "tosakbd: Unable to register input device, "
- "error: %d\n", error);
- goto fail2;
- }
-
- printk(KERN_INFO "input: Tosa Keyboard Registered\n");
-
- return 0;
-
-fail2:
- while (--i >= 0)
- gpio_free(TOSA_GPIO_KEY_STROBE(i));
-
- i = TOSA_KEY_SENSE_NUM;
-fail:
- while (--i >= 0) {
- free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), pdev);
- gpio_free(TOSA_GPIO_KEY_SENSE(i));
- }
-
- platform_set_drvdata(pdev, NULL);
- input_free_device(input_dev);
- kfree(tosakbd);
-
- return error;
-}
-
-static int __devexit tosakbd_remove(struct platform_device *dev)
-{
- int i;
- struct tosakbd *tosakbd = platform_get_drvdata(dev);
-
- for (i = 0; i < TOSA_KEY_STROBE_NUM; i++)
- gpio_free(TOSA_GPIO_KEY_STROBE(i));
-
- for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
- free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), dev);
- gpio_free(TOSA_GPIO_KEY_SENSE(i));
- }
-
- del_timer_sync(&tosakbd->timer);
-
- input_unregister_device(tosakbd->input);
-
- kfree(tosakbd);
-
- return 0;
-}
-
-static struct platform_driver tosakbd_driver = {
- .probe = tosakbd_probe,
- .remove = __devexit_p(tosakbd_remove),
- .suspend = tosakbd_suspend,
- .resume = tosakbd_resume,
- .driver = {
- .name = "tosa-keyboard",
- .owner = THIS_MODULE,
- },
-};
-
-static int __devinit tosakbd_init(void)
-{
- return platform_driver_register(&tosakbd_driver);
-}
-
-static void __exit tosakbd_exit(void)
-{
- platform_driver_unregister(&tosakbd_driver);
-}
-
-module_init(tosakbd_init);
-module_exit(tosakbd_exit);
-
-MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
-MODULE_DESCRIPTION("Tosa Keyboard Driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:tosa-keyboard");
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
index 614b65d78fe9..e8bbc619f6df 100644
--- a/drivers/input/misc/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -98,10 +98,12 @@
* Module and Version Information, Module Parameters
*/
-#define ATI_REMOTE_VENDOR_ID 0x0bc7
-#define ATI_REMOTE_PRODUCT_ID 0x004
-#define LOLA_REMOTE_PRODUCT_ID 0x002
-#define MEDION_REMOTE_PRODUCT_ID 0x006
+#define ATI_REMOTE_VENDOR_ID 0x0bc7
+#define LOLA_REMOTE_PRODUCT_ID 0x0002
+#define LOLA2_REMOTE_PRODUCT_ID 0x0003
+#define ATI_REMOTE_PRODUCT_ID 0x0004
+#define NVIDIA_REMOTE_PRODUCT_ID 0x0005
+#define MEDION_REMOTE_PRODUCT_ID 0x0006
#define DRIVER_VERSION "2.2.1"
#define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>"
@@ -142,8 +144,10 @@ MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec
#define err(format, arg...) printk(KERN_ERR format , ## arg)
static struct usb_device_id ati_remote_table[] = {
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID) },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID) },
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID) },
{} /* Terminating entry */
};
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index ea4e1fd12651..f080dd31499b 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -30,7 +30,7 @@ MODULE_ALIAS("platform:pcspkr");
#include <asm/i8253.h>
#else
#include <asm/8253pit.h>
-static DEFINE_SPINLOCK(i8253_lock);
+static DEFINE_RAW_SPINLOCK(i8253_lock);
#endif
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -50,7 +50,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
if (value > 20 && value < 32767)
count = PIT_TICK_RATE / value;
- spin_lock_irqsave(&i8253_lock, flags);
+ raw_spin_lock_irqsave(&i8253_lock, flags);
if (count) {
/* set command for counter 2, 2 byte write */
@@ -65,7 +65,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
outb(inb_p(0x61) & 0xFC, 0x61);
}
- spin_unlock_irqrestore(&i8253_lock, flags);
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
return 0;
}
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 0d22cb9ce42e..99d58764ef03 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -64,7 +64,6 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
- { { 0x73, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, /* HP Pavilion dm3 */
{ { 0x52, 0x01, 0x14 }, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
};
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index a138b5da79f9..112b4ee52ff2 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -25,6 +25,10 @@
printk(KERN_DEBUG format, ##arg); \
} while (0)
+static bool force_elantech;
+module_param_named(force_elantech, force_elantech, bool, 0644);
+MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default).");
+
/*
* Send a Synaptics style sliced query command
*/
@@ -181,14 +185,18 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
int fingers;
static int old_fingers;
- if (etd->fw_version_maj == 0x01) {
- /* byte 0: D U p1 p2 1 p3 R L
- byte 1: f 0 th tw x9 x8 y9 y8 */
+ if (etd->fw_version < 0x020000) {
+ /*
+ * byte 0: D U p1 p2 1 p3 R L
+ * byte 1: f 0 th tw x9 x8 y9 y8
+ */
fingers = ((packet[1] & 0x80) >> 7) +
((packet[1] & 0x30) >> 4);
} else {
- /* byte 0: n1 n0 p2 p1 1 p3 R L
- byte 1: 0 0 0 0 x9 x8 y9 y8 */
+ /*
+ * byte 0: n1 n0 p2 p1 1 p3 R L
+ * byte 1: 0 0 0 0 x9 x8 y9 y8
+ */
fingers = (packet[0] & 0xc0) >> 6;
}
@@ -202,13 +210,15 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_report_key(dev, BTN_TOUCH, fingers != 0);
- /* byte 2: x7 x6 x5 x4 x3 x2 x1 x0
- byte 3: y7 y6 y5 y4 y3 y2 y1 y0 */
+ /*
+ * byte 2: x7 x6 x5 x4 x3 x2 x1 x0
+ * byte 3: y7 y6 y5 y4 y3 y2 y1 y0
+ */
if (fingers) {
input_report_abs(dev, ABS_X,
((packet[1] & 0x0c) << 6) | packet[2]);
- input_report_abs(dev, ABS_Y, ETP_YMAX_V1 -
- (((packet[1] & 0x03) << 8) | packet[3]));
+ input_report_abs(dev, ABS_Y,
+ ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3]));
}
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
@@ -217,7 +227,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
- if ((etd->fw_version_maj == 0x01) &&
+ if (etd->fw_version < 0x020000 &&
(etd->capabilities & ETP_CAP_HAS_ROCKER)) {
/* rocker up */
input_report_key(dev, BTN_FORWARD, packet[0] & 0x40);
@@ -247,34 +257,47 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
switch (fingers) {
case 1:
- /* byte 1: x15 x14 x13 x12 x11 x10 x9 x8
- byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */
- input_report_abs(dev, ABS_X, (packet[1] << 8) | packet[2]);
- /* byte 4: y15 y14 y13 y12 y11 y10 y8 y8
- byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */
- input_report_abs(dev, ABS_Y, ETP_YMAX_V2 -
- ((packet[4] << 8) | packet[5]));
+ /*
+ * byte 1: . . . . . x10 x9 x8
+ * byte 2: x7 x6 x5 x4 x4 x2 x1 x0
+ */
+ input_report_abs(dev, ABS_X,
+ ((packet[1] & 0x07) << 8) | packet[2]);
+ /*
+ * byte 4: . . . . . . y9 y8
+ * byte 5: y7 y6 y5 y4 y3 y2 y1 y0
+ */
+ input_report_abs(dev, ABS_Y,
+ ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
break;
case 2:
- /* The coordinate of each finger is reported separately with
- a lower resolution for two finger touches */
- /* byte 0: . . ay8 ax8 . . . .
- byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */
+ /*
+ * The coordinate of each finger is reported separately
+ * with a lower resolution for two finger touches:
+ * byte 0: . . ay8 ax8 . . . .
+ * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
+ */
x1 = ((packet[0] & 0x10) << 4) | packet[1];
/* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */
y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]);
- /* byte 3: . . by8 bx8 . . . .
- byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */
+ /*
+ * byte 3: . . by8 bx8 . . . .
+ * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
+ */
x2 = ((packet[3] & 0x10) << 4) | packet[4];
/* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */
y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]);
- /* For compatibility with the X Synaptics driver scale up one
- coordinate and report as ordinary mouse movent */
+ /*
+ * For compatibility with the X Synaptics driver scale up
+ * one coordinate and report as ordinary mouse movent
+ */
input_report_abs(dev, ABS_X, x1 << 2);
input_report_abs(dev, ABS_Y, y1 << 2);
- /* For compatibility with the proprietary X Elantech driver
- report both coordinates as hat coordinates */
+ /*
+ * For compatibility with the proprietary X Elantech driver
+ * report both coordinates as hat coordinates
+ */
input_report_abs(dev, ABS_HAT0X, x1);
input_report_abs(dev, ABS_HAT0Y, y1);
input_report_abs(dev, ABS_HAT1X, x2);
@@ -298,7 +321,7 @@ static int elantech_check_parity_v1(struct psmouse *psmouse)
unsigned char p1, p2, p3;
/* Parity bits are placed differently */
- if (etd->fw_version_maj == 0x01) {
+ if (etd->fw_version < 0x020000) {
/* byte 0: D U p1 p2 1 p3 R L */
p1 = (packet[0] & 0x20) >> 5;
p2 = (packet[0] & 0x10) >> 4;
@@ -434,7 +457,7 @@ static void elantech_set_input_params(struct psmouse *psmouse)
switch (etd->hw_version) {
case 1:
/* Rocker button */
- if ((etd->fw_version_maj == 0x01) &&
+ if (etd->fw_version < 0x020000 &&
(etd->capabilities & ETP_CAP_HAS_ROCKER)) {
__set_bit(BTN_FORWARD, dev->keybit);
__set_bit(BTN_BACK, dev->keybit);
@@ -596,8 +619,12 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
param[0], param[1], param[2]);
if (param[0] == 0 || param[1] != 0) {
- pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
- return -1;
+ if (!force_elantech) {
+ pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
+ return -1;
+ }
+
+ pr_debug("elantech.c: Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n");
}
if (set_properties) {
@@ -659,14 +686,14 @@ int elantech_init(struct psmouse *psmouse)
pr_err("elantech.c: failed to query firmware version.\n");
goto init_fail;
}
- etd->fw_version_maj = param[0];
- etd->fw_version_min = param[2];
+
+ etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2];
/*
* Assume every version greater than this is new EeePC style
* hardware with 6 byte packets
*/
- if (etd->fw_version_maj >= 0x02 && etd->fw_version_min >= 0x30) {
+ if (etd->fw_version >= 0x020030) {
etd->hw_version = 2;
/* For now show extra debug information */
etd->debug = 1;
@@ -676,8 +703,9 @@ int elantech_init(struct psmouse *psmouse)
etd->hw_version = 1;
etd->paritycheck = 1;
}
- pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d\n",
- etd->hw_version, etd->fw_version_maj, etd->fw_version_min);
+
+ pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d.%d\n",
+ etd->hw_version, param[0], param[1], param[2]);
if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) {
pr_err("elantech.c: failed to query capabilities.\n");
@@ -692,8 +720,8 @@ int elantech_init(struct psmouse *psmouse)
* a touch action starts causing the mouse cursor or scrolled page
* to jump. Enable a workaround.
*/
- if (etd->fw_version_maj == 0x02 && etd->fw_version_min == 0x22) {
- pr_info("elantech.c: firmware version 2.34 detected, "
+ if (etd->fw_version == 0x020022) {
+ pr_info("elantech.c: firmware version 2.0.34 detected, "
"enabling jumpy cursor workaround\n");
etd->jumpy_cursor = 1;
}
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index feac5f7af966..ac57bde1bb9f 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -100,11 +100,10 @@ struct elantech_data {
unsigned char reg_26;
unsigned char debug;
unsigned char capabilities;
- unsigned char fw_version_maj;
- unsigned char fw_version_min;
- unsigned char hw_version;
unsigned char paritycheck;
unsigned char jumpy_cursor;
+ unsigned char hw_version;
+ unsigned int fw_version;
unsigned char parity[256];
};
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index d8c0c8d6992c..a3c97315a473 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -110,6 +110,7 @@ static struct workqueue_struct *kpsmoused_wq;
struct psmouse_protocol {
enum psmouse_type type;
bool maxproto;
+ bool ignore_parity; /* Protocol should ignore parity errors from KBC */
const char *name;
const char *alias;
int (*detect)(struct psmouse *, bool);
@@ -288,7 +289,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (psmouse->state == PSMOUSE_IGNORE)
goto out;
- if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
+ if (unlikely((flags & SERIO_TIMEOUT) ||
+ ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) {
+
if (psmouse->state == PSMOUSE_ACTIVATED)
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
@@ -759,6 +762,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "PS/2",
.alias = "bare",
.maxproto = true,
+ .ignore_parity = true,
.detect = ps2bare_detect,
},
#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
@@ -786,6 +790,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "ImPS/2",
.alias = "imps",
.maxproto = true,
+ .ignore_parity = true,
.detect = intellimouse_detect,
},
{
@@ -793,6 +798,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.name = "ImExPS/2",
.alias = "exps",
.maxproto = true,
+ .ignore_parity = true,
.detect = im_explorer_detect,
},
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
@@ -1222,6 +1228,7 @@ static void psmouse_disconnect(struct serio *serio)
static int psmouse_switch_protocol(struct psmouse *psmouse,
const struct psmouse_protocol *proto)
{
+ const struct psmouse_protocol *selected_proto;
struct input_dev *input_dev = psmouse->dev;
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
@@ -1245,9 +1252,14 @@ static int psmouse_switch_protocol(struct psmouse *psmouse,
return -1;
psmouse->type = proto->type;
- } else
+ selected_proto = proto;
+ } else {
psmouse->type = psmouse_extensions(psmouse,
psmouse_max_proto, true);
+ selected_proto = psmouse_protocol_by_type(psmouse->type);
+ }
+
+ psmouse->ignore_parity = selected_proto->ignore_parity;
/*
* If mouse's packet size is 3 there is no point in polling the
@@ -1267,7 +1279,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse,
psmouse->resync_time = 0;
snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",
- psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+ selected_proto->name, psmouse->vendor, psmouse->name);
input_dev->name = psmouse->devname;
input_dev->phys = psmouse->phys;
@@ -1382,6 +1394,7 @@ static int psmouse_reconnect(struct serio *serio)
struct psmouse *psmouse = serio_get_drvdata(serio);
struct psmouse *parent = NULL;
struct serio_driver *drv = serio->drv;
+ unsigned char type;
int rc = -1;
if (!drv || !psmouse) {
@@ -1401,10 +1414,15 @@ static int psmouse_reconnect(struct serio *serio)
if (psmouse->reconnect) {
if (psmouse->reconnect(psmouse))
goto out;
- } else if (psmouse_probe(psmouse) < 0 ||
- psmouse->type != psmouse_extensions(psmouse,
- psmouse_max_proto, false)) {
- goto out;
+ } else {
+ psmouse_reset(psmouse);
+
+ if (psmouse_probe(psmouse) < 0)
+ goto out;
+
+ type = psmouse_extensions(psmouse, psmouse_max_proto, false);
+ if (psmouse->type != type)
+ goto out;
}
/* ok, the device type (and capabilities) match the old one,
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index e053bdd137ff..593e910bfc7a 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -47,6 +47,7 @@ struct psmouse {
unsigned char pktcnt;
unsigned char pktsize;
unsigned char type;
+ bool ignore_parity;
bool acks_disable_command;
unsigned int model;
unsigned long last;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 026df6010161..ebd7a99efeae 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -137,7 +137,8 @@ static int synaptics_capability(struct psmouse *psmouse)
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
- priv->ext_cap = 0;
+ priv->ext_cap = priv->ext_cap_0c = 0;
+
if (!SYN_CAP_VALID(priv->capabilities))
return -1;
@@ -150,7 +151,7 @@ static int synaptics_capability(struct psmouse *psmouse)
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
- " but I'm not able to read them.");
+ " but I'm not able to read them.\n");
} else {
priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
@@ -162,6 +163,16 @@ static int synaptics_capability(struct psmouse *psmouse)
priv->ext_cap &= 0xff0fff;
}
}
+
+ if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) {
+ if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) {
+ printk(KERN_ERR "Synaptics claims to have extended capability 0x0c,"
+ " but I'm not able to read it.\n");
+ } else {
+ priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2];
+ }
+ }
+
return 0;
}
@@ -348,7 +359,15 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data
hw->left = (buf[0] & 0x01) ? 1 : 0;
hw->right = (buf[0] & 0x02) ? 1 : 0;
- if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
+ if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+ /*
+ * Clickpad's button is transmitted as middle button,
+ * however, since it is primary button, we will report
+ * it as BTN_LEFT.
+ */
+ hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
+
+ } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) {
hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
if (hw->w == 2)
hw->scroll = (signed char)(buf[1]);
@@ -593,6 +612,12 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
dev->absres[ABS_X] = priv->x_res;
dev->absres[ABS_Y] = priv->y_res;
+
+ if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+ /* Clickpads report only left button */
+ __clear_bit(BTN_RIGHT, dev->keybit);
+ __clear_bit(BTN_MIDDLE, dev->keybit);
+ }
}
static void synaptics_disconnect(struct psmouse *psmouse)
@@ -697,10 +722,10 @@ int synaptics_init(struct psmouse *psmouse)
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
- printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n",
+ printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n",
SYN_ID_MODEL(priv->identity),
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
- priv->model_id, priv->capabilities, priv->ext_cap);
+ priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c);
set_input_params(psmouse->dev, priv);
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index f0f40a331dc8..ae37c5d162a4 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -18,6 +18,7 @@
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
#define SYN_QUE_EXT_CAPAB 0x09
+#define SYN_QUE_EXT_CAPAB_0C 0x0c
/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
@@ -48,6 +49,8 @@
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
+#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
+#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100)
/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -96,6 +99,7 @@ struct synaptics_data {
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
unsigned long int ext_cap; /* Extended Capabilities */
+ unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */
unsigned long int identity; /* Identification */
int x_res; /* X resolution in units/mm */
int y_res; /* Y resolution in units/mm */
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 77a50d9bba17..6c0f1712f55b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -99,22 +99,6 @@ config TOUCHSCREEN_BITSY
To compile this driver as a module, choose M here: the
module will be called h3600_ts_input.
-config TOUCHSCREEN_CORGI
- tristate "SharpSL (Corgi and Spitz series) touchscreen driver (DEPRECATED)"
- depends on PXA_SHARPSL
- select CORGI_SSP_DEPRECATED
- help
- Say Y here to enable the driver for the touchscreen on the
- Sharp SL-C7xx and SL-Cxx00 series of PDAs.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called corgi_ts.
-
- NOTE: this driver is deprecated, try enable SPI and generic
- ADS7846-based touchscreen driver.
-
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7fef7d5cca23..41145d074dec 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index e019d53d1ab4..0d2d7e54b465 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -156,9 +156,14 @@ struct ser_req {
u16 reset;
u16 ref_on;
u16 command;
- u16 sample;
struct spi_message msg;
struct spi_transfer xfer[6];
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ u16 sample ____cacheline_aligned;
};
struct ad7877 {
@@ -182,8 +187,6 @@ struct ad7877 {
u8 averaging;
u8 pen_down_acc_interval;
- u16 conversion_data[AD7877_NR_SENSE];
-
struct spi_transfer xfer[AD7877_NR_SENSE + 2];
struct spi_message msg;
@@ -195,6 +198,12 @@ struct ad7877 {
spinlock_t lock;
struct timer_list timer; /* P: lock */
unsigned pending:1; /* P: lock */
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ u16 conversion_data[AD7877_NR_SENSE] ____cacheline_aligned;
};
static int gpio3;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
deleted file mode 100644
index 94a1919d439d..000000000000
--- a/drivers/input/touchscreen/corgi_ts.c
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Touchscreen driver for Sharp SL-C7xx and SL-Cxx00 models
- *
- * Copyright (c) 2004-2005 Richard Purdie
- *
- * 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/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <mach/sharpsl.h>
-#include <mach/hardware.h>
-#include <mach/pxa2xx-gpio.h>
-
-
-#define PWR_MODE_ACTIVE 0
-#define PWR_MODE_SUSPEND 1
-
-#define X_AXIS_MAX 3830
-#define X_AXIS_MIN 150
-#define Y_AXIS_MAX 3830
-#define Y_AXIS_MIN 190
-#define PRESSURE_MIN 0
-#define PRESSURE_MAX 15000
-
-struct ts_event {
- short pressure;
- short x;
- short y;
-};
-
-struct corgi_ts {
- struct input_dev *input;
- struct timer_list timer;
- struct ts_event tc;
- int pendown;
- int power_mode;
- int irq_gpio;
- struct corgits_machinfo *machinfo;
-};
-
-#ifdef CONFIG_PXA25x
-#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a))
-#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x))
-#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x))
-#endif
-#ifdef CONFIG_PXA27x
-#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
-#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C1, 0" : "=r"(x))
-#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C1, 0" : : "r"(x))
-#endif
-
-/* ADS7846 Touch Screen Controller bit definitions */
-#define ADSCTRL_PD0 (1u << 0) /* PD0 */
-#define ADSCTRL_PD1 (1u << 1) /* PD1 */
-#define ADSCTRL_DFR (1u << 2) /* SER/DFR */
-#define ADSCTRL_MOD (1u << 3) /* Mode */
-#define ADSCTRL_ADR_SH 4 /* Address setting */
-#define ADSCTRL_STS (1u << 7) /* Start Bit */
-
-/* External Functions */
-extern unsigned int get_clk_frequency_khz(int info);
-
-static unsigned long calc_waittime(struct corgi_ts *corgi_ts)
-{
- unsigned long hsync_invperiod = corgi_ts->machinfo->get_hsync_invperiod();
-
- if (hsync_invperiod)
- return get_clk_frequency_khz(0)*1000/hsync_invperiod;
- else
- return 0;
-}
-
-static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, int doSend,
- unsigned int address, unsigned long wait_time)
-{
- unsigned long timer1 = 0, timer2, pmnc = 0;
- int pos = 0;
-
- if (wait_time && doSend) {
- PMNC_GET(pmnc);
- if (!(pmnc & 0x01))
- PMNC_SET(0x01);
-
- /* polling HSync */
- corgi_ts->machinfo->wait_hsync();
- /* get CCNT */
- CCNT(timer1);
- }
-
- if (doRecive)
- pos = corgi_ssp_ads7846_get();
-
- if (doSend) {
- int cmd = ADSCTRL_PD0 | ADSCTRL_PD1 | (address << ADSCTRL_ADR_SH) | ADSCTRL_STS;
- /* dummy command */
- corgi_ssp_ads7846_put(cmd);
- corgi_ssp_ads7846_get();
-
- if (wait_time) {
- /* Wait after HSync */
- CCNT(timer2);
- if (timer2-timer1 > wait_time) {
- /* too slow - timeout, try again */
- corgi_ts->machinfo->wait_hsync();
- /* get CCNT */
- CCNT(timer1);
- /* Wait after HSync */
- CCNT(timer2);
- }
- while (timer2 - timer1 < wait_time)
- CCNT(timer2);
- }
- corgi_ssp_ads7846_put(cmd);
- if (wait_time && !(pmnc & 0x01))
- PMNC_SET(pmnc);
- }
- return pos;
-}
-
-static int read_xydata(struct corgi_ts *corgi_ts)
-{
- unsigned int x, y, z1, z2;
- unsigned long flags, wait_time;
-
- /* critical section */
- local_irq_save(flags);
- corgi_ssp_ads7846_lock();
- wait_time = calc_waittime(corgi_ts);
-
- /* Y-axis */
- sync_receive_data_send_cmd(corgi_ts, 0, 1, 1u, wait_time);
-
- /* Y-axis */
- sync_receive_data_send_cmd(corgi_ts, 1, 1, 1u, wait_time);
-
- /* X-axis */
- y = sync_receive_data_send_cmd(corgi_ts, 1, 1, 5u, wait_time);
-
- /* Z1 */
- x = sync_receive_data_send_cmd(corgi_ts, 1, 1, 3u, wait_time);
-
- /* Z2 */
- z1 = sync_receive_data_send_cmd(corgi_ts, 1, 1, 4u, wait_time);
- z2 = sync_receive_data_send_cmd(corgi_ts, 1, 0, 4u, wait_time);
-
- /* Power-Down Enable */
- corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- corgi_ssp_ads7846_get();
-
- corgi_ssp_ads7846_unlock();
- local_irq_restore(flags);
-
- if (x== 0 || y == 0 || z1 == 0 || (x * (z2 - z1) / z1) >= 15000) {
- corgi_ts->tc.pressure = 0;
- return 0;
- }
-
- corgi_ts->tc.x = x;
- corgi_ts->tc.y = y;
- corgi_ts->tc.pressure = (x * (z2 - z1)) / z1;
- return 1;
-}
-
-static void new_data(struct corgi_ts *corgi_ts)
-{
- struct input_dev *dev = corgi_ts->input;
-
- if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
- return;
-
- if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
- return;
-
- input_report_abs(dev, ABS_X, corgi_ts->tc.x);
- input_report_abs(dev, ABS_Y, corgi_ts->tc.y);
- input_report_abs(dev, ABS_PRESSURE, corgi_ts->tc.pressure);
- input_report_key(dev, BTN_TOUCH, corgi_ts->pendown);
- input_sync(dev);
-}
-
-static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer)
-{
- if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) {
- /* Disable Interrupt */
- set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_NONE);
- if (read_xydata(corgi_ts)) {
- corgi_ts->pendown = 1;
- new_data(corgi_ts);
- }
- mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
- } else {
- if (corgi_ts->pendown == 1 || corgi_ts->pendown == 2) {
- mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
- corgi_ts->pendown++;
- return;
- }
-
- if (corgi_ts->pendown) {
- corgi_ts->tc.pressure = 0;
- new_data(corgi_ts);
- }
-
- /* Enable Falling Edge */
- set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING);
- corgi_ts->pendown = 0;
- }
-}
-
-static void corgi_ts_timer(unsigned long data)
-{
- struct corgi_ts *corgits_data = (struct corgi_ts *) data;
-
- ts_interrupt_main(corgits_data, 1);
-}
-
-static irqreturn_t ts_interrupt(int irq, void *dev_id)
-{
- struct corgi_ts *corgits_data = dev_id;
-
- ts_interrupt_main(corgits_data, 0);
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_PM
-static int corgits_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct corgi_ts *corgi_ts = platform_get_drvdata(dev);
-
- if (corgi_ts->pendown) {
- del_timer_sync(&corgi_ts->timer);
- corgi_ts->tc.pressure = 0;
- new_data(corgi_ts);
- corgi_ts->pendown = 0;
- }
- corgi_ts->power_mode = PWR_MODE_SUSPEND;
-
- corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
-
- return 0;
-}
-
-static int corgits_resume(struct platform_device *dev)
-{
- struct corgi_ts *corgi_ts = platform_get_drvdata(dev);
-
- corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- /* Enable Falling Edge */
- set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING);
- corgi_ts->power_mode = PWR_MODE_ACTIVE;
-
- return 0;
-}
-#else
-#define corgits_suspend NULL
-#define corgits_resume NULL
-#endif
-
-static int __devinit corgits_probe(struct platform_device *pdev)
-{
- struct corgi_ts *corgi_ts;
- struct input_dev *input_dev;
- int err = -ENOMEM;
-
- corgi_ts = kzalloc(sizeof(struct corgi_ts), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!corgi_ts || !input_dev)
- goto fail1;
-
- platform_set_drvdata(pdev, corgi_ts);
-
- corgi_ts->machinfo = pdev->dev.platform_data;
- corgi_ts->irq_gpio = platform_get_irq(pdev, 0);
-
- if (corgi_ts->irq_gpio < 0) {
- err = -ENODEV;
- goto fail1;
- }
-
- corgi_ts->input = input_dev;
-
- init_timer(&corgi_ts->timer);
- corgi_ts->timer.data = (unsigned long) corgi_ts;
- corgi_ts->timer.function = corgi_ts_timer;
-
- input_dev->name = "Corgi Touchscreen";
- input_dev->phys = "corgits/input0";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0002;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &pdev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
-
- pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN);
-
- /* Initiaize ADS7846 Difference Reference mode */
- corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- mdelay(5);
- corgi_ssp_ads7846_putget((3u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- mdelay(5);
- corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- mdelay(5);
- corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
- mdelay(5);
-
- if (request_irq(corgi_ts->irq_gpio, ts_interrupt, IRQF_DISABLED, "ts", corgi_ts)) {
- err = -EBUSY;
- goto fail1;
- }
-
- err = input_register_device(corgi_ts->input);
- if (err)
- goto fail2;
-
- corgi_ts->power_mode = PWR_MODE_ACTIVE;
-
- /* Enable Falling Edge */
- set_irq_type(corgi_ts->irq_gpio, IRQ_TYPE_EDGE_FALLING);
-
- return 0;
-
- fail2: free_irq(corgi_ts->irq_gpio, corgi_ts);
- fail1: input_free_device(input_dev);
- kfree(corgi_ts);
- return err;
-}
-
-static int __devexit corgits_remove(struct platform_device *pdev)
-{
- struct corgi_ts *corgi_ts = platform_get_drvdata(pdev);
-
- free_irq(corgi_ts->irq_gpio, corgi_ts);
- del_timer_sync(&corgi_ts->timer);
- corgi_ts->machinfo->put_hsync();
- input_unregister_device(corgi_ts->input);
- kfree(corgi_ts);
-
- return 0;
-}
-
-static struct platform_driver corgits_driver = {
- .probe = corgits_probe,
- .remove = __devexit_p(corgits_remove),
- .suspend = corgits_suspend,
- .resume = corgits_resume,
- .driver = {
- .name = "corgi-ts",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init corgits_init(void)
-{
- return platform_driver_register(&corgits_driver);
-}
-
-static void __exit corgits_exit(void)
-{
- platform_driver_unregister(&corgits_driver);
-}
-
-module_init(corgits_init);
-module_exit(corgits_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-MODULE_DESCRIPTION("Corgi TouchScreen Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:corgi-ts");
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 204b8a1a601c..75f8b73010fa 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -124,14 +124,25 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int eeti_ts_open(struct input_dev *dev)
+static void eeti_ts_start(struct eeti_ts_priv *priv)
{
- struct eeti_ts_priv *priv = input_get_drvdata(dev);
-
enable_irq(priv->irq);
/* Read the events once to arm the IRQ */
eeti_ts_read(&priv->work);
+}
+
+static void eeti_ts_stop(struct eeti_ts_priv *priv)
+{
+ disable_irq(priv->irq);
+ cancel_work_sync(&priv->work);
+}
+
+static int eeti_ts_open(struct input_dev *dev)
+{
+ struct eeti_ts_priv *priv = input_get_drvdata(dev);
+
+ eeti_ts_start(priv);
return 0;
}
@@ -140,8 +151,7 @@ static void eeti_ts_close(struct input_dev *dev)
{
struct eeti_ts_priv *priv = input_get_drvdata(dev);
- disable_irq(priv->irq);
- cancel_work_sync(&priv->work);
+ eeti_ts_stop(priv);
}
static int __devinit eeti_ts_probe(struct i2c_client *client,
@@ -153,10 +163,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
unsigned int irq_flags;
int err = -ENOMEM;
- /* In contrast to what's described in the datasheet, there seems
+ /*
+ * In contrast to what's described in the datasheet, there seems
* to be no way of probing the presence of that device using I2C
* commands. So we need to blindly believe it is there, and wait
- * for interrupts to occur. */
+ * for interrupts to occur.
+ */
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
@@ -212,9 +224,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
goto err2;
}
- /* Disable the irq for now. It will be enabled once the input device
- * is opened. */
- disable_irq(priv->irq);
+ /*
+ * Disable the device for now. It will be enabled once the
+ * input device is opened.
+ */
+ eeti_ts_stop(priv);
device_init_wakeup(&client->dev, 0);
return 0;
@@ -235,6 +249,12 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
free_irq(priv->irq, priv);
+ /*
+ * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it
+ * so that device still works if we reload the driver.
+ */
+ enable_irq(priv->irq);
+
input_unregister_device(priv->input);
i2c_set_clientdata(client, NULL);
kfree(priv);
@@ -246,6 +266,14 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+ struct input_dev *input_dev = priv->input;
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ eeti_ts_stop(priv);
+
+ mutex_unlock(&input_dev->mutex);
if (device_may_wakeup(&client->dev))
enable_irq_wake(priv->irq);
@@ -256,10 +284,18 @@ static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
static int eeti_ts_resume(struct i2c_client *client)
{
struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+ struct input_dev *input_dev = priv->input;
if (device_may_wakeup(&client->dev))
disable_irq_wake(priv->irq);
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ eeti_ts_start(priv);
+
+ mutex_unlock(&input_dev->mutex);
+
return 0;
}
#else
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9712b2e97be4..cefd63daff31 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2109,12 +2109,18 @@ repeat:
if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */
/* .. if the array isn't clean, an 'even' event must also go
* to spares. */
- if ((mddev->events&1)==0)
+ if ((mddev->events&1)==0) {
nospares = 0;
+ sync_req = 2; /* force a second update to get the
+ * even/odd in sync */
+ }
} else {
/* otherwise an 'odd' event must go to spares */
- if ((mddev->events&1))
+ if ((mddev->events&1)) {
nospares = 0;
+ sync_req = 2; /* force a second update to get the
+ * even/odd in sync */
+ }
}
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 58ea0ecae7c3..15348c393b5d 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1527,7 +1527,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
atomic_inc(&rdev->read_errors);
- if (conf->mddev->degraded)
+ if (conf->mddev->degraded >= conf->max_degraded)
printk_rl(KERN_WARNING
"raid5:%s: read error not correctable "
"(sector %llu on %s).\n",
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index fd8e1f45be36..7364b9642d00 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -423,15 +423,14 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
}
}
-int saa7146_vv_devinit(struct saa7146_dev *dev)
-{
- return v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
-}
-EXPORT_SYMBOL_GPL(saa7146_vv_devinit);
-
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
{
struct saa7146_vv *vv;
+ int err;
+
+ err = v4l2_device_register(&dev->pci->dev, &dev->v4l2_dev);
+ if (err)
+ return err;
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
if (vv == NULL) {
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 5ed75263340a..b8b2c551a1e2 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -558,9 +558,11 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
/* ok, accept it */
vv->ov_fb = *fb;
vv->ov_fmt = fmt;
- if (0 == vv->ov_fb.fmt.bytesperline)
- vv->ov_fb.fmt.bytesperline =
- vv->ov_fb.fmt.width * fmt->depth / 8;
+
+ if (vv->ov_fb.fmt.bytesperline < vv->ov_fb.fmt.width) {
+ vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
+ DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
+ }
mutex_unlock(&dev->lock);
return 0;
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index a3c07fe0e6c4..96972804f4ad 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -4470,6 +4470,10 @@ static int stv090x_setup(struct dvb_frontend *fe)
if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
goto err;
+ /* workaround for stuck DiSEqC output */
+ if (config->diseqc_envelope_mode)
+ stv090x_send_diseqc_burst(fe, SEC_MINI_A);
+
return 0;
err:
dprintk(FE_ERROR, 1, "I/O error");
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 9fdf26cc6998..1500210c06cf 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -643,9 +643,6 @@ static void frontend_init(struct budget *budget)
&budget->i2c_adap,
&tt1600_isl6423_config);
- } else {
- dvb_frontend_detach(budget->dvb_frontend);
- budget->dvb_frontend = NULL;
}
}
break;
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index f8fc8654693d..9644cf760aaa 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -361,7 +361,7 @@ config VIDEO_SAA717X
config VIDEO_SAA7191
tristate "Philips SAA7191 video decoder"
- depends on VIDEO_V4L1 && I2C
+ depends on VIDEO_V4L2 && I2C
---help---
Support for the Philips SAA7191 video decoder.
@@ -756,7 +756,7 @@ source "drivers/media/video/saa7134/Kconfig"
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
- depends on PCI && VIDEO_V4L1 && I2C
+ depends on PCI && VIDEO_V4L2 && I2C
select VIDEO_SAA7146_VV
select VIDEO_TUNER
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index b88b6174a331..c51c386559f2 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -160,8 +160,6 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
-obj-$(CONFIG_ARCH_DAVINCI) += davinci/
-
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 7cf042f9b377..398dbe71cb82 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -223,7 +223,6 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev)
BUG_ON(!dev->hw_ops.get_frame_format);
BUG_ON(!dev->hw_ops.get_pixel_format);
BUG_ON(!dev->hw_ops.set_pixel_format);
- BUG_ON(!dev->hw_ops.set_params);
BUG_ON(!dev->hw_ops.set_image_window);
BUG_ON(!dev->hw_ops.get_image_window);
BUG_ON(!dev->hw_ops.get_line_length);
@@ -1689,11 +1688,12 @@ static long vpfe_param_handler(struct file *file, void *priv,
struct vpfe_device *vpfe_dev = video_drvdata(file);
int ret = 0;
- v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
+ v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n");
if (vpfe_dev->started) {
/* only allowed if streaming is not started */
- v4l2_err(&vpfe_dev->v4l2_dev, "device already started\n");
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "device already started\n");
return -EBUSY;
}
@@ -1705,16 +1705,23 @@ static long vpfe_param_handler(struct file *file, void *priv,
case VPFE_CMD_S_CCDC_RAW_PARAMS:
v4l2_warn(&vpfe_dev->v4l2_dev,
"VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n");
- ret = ccdc_dev->hw_ops.set_params(param);
- if (ret) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Error in setting parameters in CCDC\n");
- goto unlock_out;
- }
- if (vpfe_get_ccdc_image_format(vpfe_dev, &vpfe_dev->fmt) < 0) {
- v4l2_err(&vpfe_dev->v4l2_dev,
- "Invalid image format at CCDC\n");
- goto unlock_out;
+ if (ccdc_dev->hw_ops.set_params) {
+ ret = ccdc_dev->hw_ops.set_params(param);
+ if (ret) {
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "Error setting parameters in CCDC\n");
+ goto unlock_out;
+ }
+ if (vpfe_get_ccdc_image_format(vpfe_dev,
+ &vpfe_dev->fmt) < 0) {
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "Invalid image format at CCDC\n");
+ goto unlock_out;
+ }
+ } else {
+ ret = -EINVAL;
+ v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
+ "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n");
}
break;
default:
@@ -1830,7 +1837,7 @@ static __init int vpfe_probe(struct platform_device *pdev)
if (NULL == ccdc_cfg) {
v4l2_err(pdev->dev.driver,
"Memory allocation failed for ccdc_cfg\n");
- goto probe_free_dev_mem;
+ goto probe_free_lock;
}
strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
@@ -1982,8 +1989,9 @@ probe_out_video_release:
probe_out_release_irq:
free_irq(vpfe_dev->ccdc_irq0, vpfe_dev);
probe_free_ccdc_cfg_mem:
- mutex_unlock(&ccdc_lock);
kfree(ccdc_cfg);
+probe_free_lock:
+ mutex_unlock(&ccdc_lock);
probe_free_dev_mem:
kfree(vpfe_dev);
return ret;
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 38a6e15e096b..3dee3e5844b6 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1427,7 +1427,7 @@ static int input_kthread(void *data)
struct gspca_dev *gspca_dev = (struct gspca_dev *)data;
struct sd *sd = (struct sd *) gspca_dev;
- DECLARE_WAIT_QUEUE_HEAD(wait);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait);
set_freezable();
for (;;) {
if (kthread_should_stop())
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 15b2eef8a3f6..edf0fe157501 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1513,7 +1513,6 @@ static const struct sd_desc sd_desc = {
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam},
{USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista},
- {USB_DEVICE(0x0461, 0x0815), .driver_info = MicroInnovationIC200},
{USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110},
{USB_DEVICE(0x0af9, 0x0010), .driver_info = HamaUSBSightcam},
{USB_DEVICE(0x0af9, 0x0011), .driver_info = HamaUSBSightcam2},
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index dc7f2b0fbc79..b9c80e2103b9 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -1053,6 +1053,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
{USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
{USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
+ {USB_DEVICE(0x0461, 0x0815), .driver_info = Rev072A},
{USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A},
{USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A},
{USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A},
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index af73da34c83f..14f179a19485 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -524,8 +524,6 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 },
/* QuickCam Messenger (new) */
{USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 },
- /* QuickCam Messenger (new) */
- {USB_DEVICE(0x046D, 0x08DA), .driver_info = BRIDGE_ST6422 },
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index e620a3a92f25..ad2c232baa6d 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -356,9 +356,6 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
DEB_EE((".\n"));
- ret = saa7146_vv_devinit(dev);
- if (ret)
- return ret;
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index fe596a1c12a8..938a1f8f880a 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -216,10 +216,6 @@ static int hexium_probe(struct saa7146_dev *dev)
return -EFAULT;
}
- err = saa7146_vv_devinit(dev);
- if (err)
- return err;
-
hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
if (NULL == hexium) {
printk("hexium_orion: hexium_probe: not enough kernel memory.\n");
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 3c8ebfcb742e..34a66019190e 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -49,8 +49,6 @@
/*
* CSI registers
*/
-#define DMA_CCR(x) (0x8c + ((x) << 6)) /* Control Registers */
-#define DMA_DIMR 0x08 /* Interrupt mask Register */
#define CSICR1 0x00 /* CSI Control Register 1 */
#define CSISR 0x08 /* CSI Status Register */
#define CSIRXR 0x10 /* CSI RxFIFO Register */
@@ -784,7 +782,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
pcdev);
imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32, DMA_REQ_CSI_R, 0);
+ IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0);
/* burst length : 16 words = 64 bytes */
imx_dma_config_burstlen(pcdev->dma_chan, 0);
@@ -798,8 +796,8 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end -
&mx1_camera_sof_fiq_start);
- regs.ARM_r8 = DMA_BASE + DMA_DIMR;
- regs.ARM_r9 = DMA_BASE + DMA_CCR(pcdev->dma_chan);
+ regs.ARM_r8 = (long)MX1_DMA_DIMR;
+ regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan);
regs.ARM_r10 = (long)pcdev->base + CSICR1;
regs.ARM_fp = (long)pcdev->base + CSISR;
regs.ARM_sp = 1 << pcdev->dma_chan;
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 9f01f14e4aa2..ef0c8178f255 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -169,11 +169,7 @@ static struct saa7146_extension extension;
static int mxb_probe(struct saa7146_dev *dev)
{
struct mxb *mxb = NULL;
- int err;
- err = saa7146_vv_devinit(dev);
- if (err)
- return err;
mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
if (mxb == NULL) {
DEB_D(("not enough kernel memory.\n"));
@@ -699,14 +695,17 @@ static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
- struct mxb *mxb = (struct mxb *)dev->ext_priv;
+ struct mxb *mxb;
DEB_EE(("dev:%p\n", dev));
- /* checking for i2c-devices can be omitted here, because we
- already did this in "mxb_vl42_probe" */
-
saa7146_vv_init(dev, &vv_data);
+ if (mxb_probe(dev)) {
+ saa7146_vv_release(dev);
+ return -1;
+ }
+ mxb = (struct mxb *)dev->ext_priv;
+
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
@@ -726,6 +725,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
vv_data.ops.vidioc_default = vidioc_default;
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR(("cannot register capture v4l2 device. skipping.\n"));
+ saa7146_vv_release(dev);
return -1;
}
@@ -846,7 +846,6 @@ static struct saa7146_extension extension = {
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
- .probe = mxb_probe,
.attach = mxb_attach,
.detach = mxb_detach,
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index b189fe63394b..ce76d952e161 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1405,7 +1405,7 @@ static int omap24xxcam_mmap_buffers(struct file *file,
}
size = 0;
- for (i = first; i <= last; i++) {
+ for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) {
struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
for (j = 0; j < dma->sglen; j++) {
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 5ecc30daef2d..04bf5c11308d 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -609,12 +609,9 @@ static void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev,
*/
static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
{
- unsigned long cicr0, cifr;
+ unsigned long cicr0;
dev_dbg(pcdev->soc_host.v4l2_dev.dev, "%s\n", __func__);
- /* Reset the FIFOs */
- cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
- __raw_writel(cifr, pcdev->base + CIFR);
/* Enable End-Of-Frame Interrupt */
cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB;
cicr0 &= ~CICR0_EOFM;
@@ -935,7 +932,7 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
static irqreturn_t pxa_camera_irq(int irq, void *data)
{
struct pxa_camera_dev *pcdev = data;
- unsigned long status, cicr0;
+ unsigned long status, cifr, cicr0;
struct pxa_buffer *buf;
struct videobuf_buffer *vb;
@@ -949,6 +946,10 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
__raw_writel(status, pcdev->base + CISR);
if (status & CISR_EOF) {
+ /* Reset the FIFOs */
+ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
+ __raw_writel(cifr, pcdev->base + CIFR);
+
pcdev->active = list_first_entry(&pcdev->capture,
struct pxa_buffer, vb.queue);
vb = &pcdev->active->vb;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 6e16b3979326..1ad980f8e770 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -1633,7 +1633,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
height = pix->height;
pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt);
- if (pix->bytesperline < 0)
+ if ((int)pix->bytesperline < 0)
return pix->bytesperline;
pix->sizeimage = height * pix->bytesperline;
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index a3d5728b6449..f2ab025ad97a 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -349,6 +349,9 @@ int wm831x_auxadc_read(struct wm831x *wm831x, enum wm831x_auxadc input)
goto disable;
}
+ /* If an interrupt arrived late clean up after it */
+ try_wait_for_completion(&wm831x->auxadc_done);
+
/* Ignore the result to allow us to soldier on without IRQ hookup */
wait_for_completion_timeout(&wm831x->auxadc_done, msecs_to_jiffies(5));
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index e400a3bed063..b5807484b4c9 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -363,6 +363,10 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
reg |= 1 << channel | WM8350_AUXADC_POLL;
wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
+ /* If a late IRQ left the completion signalled then consume
+ * the completion. */
+ try_wait_for_completion(&wm8350->auxadc_done);
+
/* We ignore the result of the completion and just check for a
* conversion result, allowing us to soldier on if the IRQ
* infrastructure is not set up for the chip. */
diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmware_balloon.c
index e7161c4e3798..db9cd0240c6f 100644
--- a/drivers/misc/vmware_balloon.c
+++ b/drivers/misc/vmware_balloon.c
@@ -41,7 +41,7 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#include <asm/vmware.h>
+#include <asm/hypervisor.h>
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
@@ -767,7 +767,7 @@ static int __init vmballoon_init(void)
* Check if we are running on VMware's hypervisor and bail out
* if we are not.
*/
- if (!vmware_platform())
+ if (x86_hyper != &x86_hyper_vmware)
return -ENODEV;
vmballoon_wq = create_freezeable_workqueue("vmmemctl");
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index a6dd7da37357..336d9f553f3e 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -314,8 +314,8 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
dmabuf = (unsigned *)tmpv;
}
+ flush_kernel_dcache_page(sg_page(sg));
kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
- dmac_flush_range((void *)sgbuffer, ((void *)sgbuffer) + amount);
data->bytes_xfered += amount;
if (size == 0)
break;
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 88be37d9e9a5..fb279f4ed8b3 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -266,7 +266,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
cmd->opcode, cmd->arg, cmd->flags,
cmd->resp[0], cmd->resp[1], cmd->resp[2],
- cmd->resp[2], cmd->error);
+ cmd->resp[3], cmd->error);
if (data)
seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
data->bytes_xfered, data->blocks,
@@ -276,7 +276,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
"CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
stop->opcode, stop->arg, stop->flags,
stop->resp[0], stop->resp[1], stop->resp[2],
- stop->resp[2], stop->error);
+ stop->resp[3], stop->error);
}
spin_unlock_bh(&slot->host->lock);
@@ -569,9 +569,10 @@ static void atmci_dma_cleanup(struct atmel_mci *host)
{
struct mmc_data *data = host->data;
- dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+ if (data)
+ dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+ ((data->flags & MMC_DATA_WRITE)
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
}
static void atmci_stop_dma(struct atmel_mci *host)
@@ -1099,8 +1100,8 @@ static void atmci_command_complete(struct atmel_mci *host,
"command error: status=0x%08x\n", status);
if (cmd->data) {
- host->data = NULL;
atmci_stop_dma(host);
+ host->data = NULL;
mci_writel(host, IDR, MCI_NOTBUSY
| MCI_TXRDY | MCI_RXRDY
| ATMCI_DATA_ERROR_FLAGS);
@@ -1293,6 +1294,7 @@ static void atmci_tasklet_func(unsigned long priv)
} else {
data->bytes_xfered = data->blocks * data->blksz;
data->error = 0;
+ mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS);
}
if (!data->stop) {
@@ -1751,13 +1753,13 @@ static int __init atmci_probe(struct platform_device *pdev)
ret = -ENODEV;
if (pdata->slot[0].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[0],
- MCI_SDCSEL_SLOT_A, 0);
+ 0, MCI_SDCSEL_SLOT_A);
if (!ret)
nr_slots++;
}
if (pdata->slot[1].bus_width) {
ret = atmci_init_slot(host, &pdata->slot[1],
- MCI_SDCSEL_SLOT_B, 1);
+ 1, MCI_SDCSEL_SLOT_B);
if (!ret)
nr_slots++;
}
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 84c103a7ee13..ff115d920888 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -55,14 +55,16 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
host->cclk = host->mclk / (2 * (clk + 1));
}
if (host->hw_designer == AMBA_VENDOR_ST)
- clk |= MCI_FCEN; /* Bug fix in ST IP block */
+ clk |= MCI_ST_FCEN; /* Bug fix in ST IP block */
clk |= MCI_CLK_ENABLE;
/* This hasn't proven to be worthwhile */
/* clk |= MCI_CLK_PWRSAVE; */
}
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
- clk |= MCI_WIDE_BUS;
+ clk |= MCI_4BIT_BUS;
+ if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
+ clk |= MCI_ST_8BIT_BUS;
writel(clk, host->base + MMCICLOCK);
}
@@ -629,7 +631,18 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
mmc->ops = &mmci_ops;
mmc->f_min = (host->mclk + 511) / 512;
- mmc->f_max = min(host->mclk, fmax);
+ /*
+ * If the platform data supplies a maximum operating
+ * frequency, this takes precedence. Else, we fall back
+ * to using the module parameter, which has a (low)
+ * default value in case it is not specified. Either
+ * value must not exceed the clock rate into the block,
+ * of course.
+ */
+ if (plat->f_max)
+ mmc->f_max = min(host->mclk, plat->f_max);
+ else
+ mmc->f_max = min(host->mclk, fmax);
dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
#ifdef CONFIG_REGULATOR
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 1ceb9a90f59b..d77062e5e3af 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -25,9 +25,11 @@
#define MCI_CLK_ENABLE (1 << 8)
#define MCI_CLK_PWRSAVE (1 << 9)
#define MCI_CLK_BYPASS (1 << 10)
-#define MCI_WIDE_BUS (1 << 11)
+#define MCI_4BIT_BUS (1 << 11)
+/* 8bit wide buses supported in ST Micro versions */
+#define MCI_ST_8BIT_BUS (1 << 12)
/* HW flow control on the ST Micro version */
-#define MCI_FCEN (1 << 13)
+#define MCI_ST_FCEN (1 << 13)
#define MMCIARGUMENT 0x008
#define MMCICOMMAND 0x00c
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 0ed48959b590..e4f00e70a749 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -544,7 +544,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
- mmc_detect_change(devid, host->pdata->detect_delay);
+ mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
return IRQ_HANDLED;
}
diff --git a/drivers/mtd/internal.h b/drivers/mtd/internal.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/mtd/internal.h
+++ /dev/null
diff --git a/drivers/mtd/mtdbdi.c b/drivers/mtd/mtdbdi.c
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/drivers/mtd/mtdbdi.c
+++ /dev/null
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index ed5e9742be2c..a8f0512bad38 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -674,6 +674,7 @@ static struct zorro_device_id a2065_zorro_tbl[] __devinitdata = {
{ ZORRO_PROD_AMERISTAR_A2065 },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, a2065_zorro_tbl);
static struct zorro_driver a2065_driver = {
.name = "a2065",
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index fa1a2354f5f9..4b30a46486e2 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -145,6 +145,7 @@ static struct zorro_device_id ariadne_zorro_tbl[] __devinitdata = {
{ ZORRO_PROD_VILLAGE_TRONIC_ARIADNE },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, ariadne_zorro_tbl);
static struct zorro_driver ariadne_driver = {
.name = "ariadne",
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 6995169d285a..cd17d09f385c 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -311,11 +311,6 @@ err:
processed++;
}
- if (processed) {
- wrw(ep, REG_RXDENQ, processed);
- wrw(ep, REG_RXSTSENQ, processed);
- }
-
return processed;
}
@@ -350,6 +345,11 @@ poll_some_more:
goto poll_some_more;
}
+ if (rx) {
+ wrw(ep, REG_RXDENQ, rx);
+ wrw(ep, REG_RXSTSENQ, rx);
+ }
+
return rx;
}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index fb8fc7d1b50d..dbf81788bb40 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -4633,6 +4633,9 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
reg16 &= ~state;
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
+ if (!pdev->bus->self)
+ return;
+
pos = pci_pcie_cap(pdev->bus->self);
pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, &reg16);
reg16 &= ~state;
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 9f98c1c4a344..9b4e8f797a7a 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1653,7 +1653,7 @@ fec_set_mac_address(struct net_device *dev, void *p)
(dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
fep->hwp + FEC_ADDR_LOW);
writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
- fep + FEC_ADDR_HIGH);
+ fep->hwp + FEC_ADDR_HIGH);
return 0;
}
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4e97ca182997..5d3763fb3472 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1649,6 +1649,7 @@ static void free_skb_resources(struct gfar_private *priv)
sizeof(struct rxbd8) * priv->total_rx_ring_size,
priv->tx_queue[0]->tx_bd_base,
priv->tx_queue[0]->tx_bd_dma_base);
+ skb_queue_purge(&priv->rx_recycle);
}
void gfar_start(struct net_device *dev)
@@ -2088,7 +2089,6 @@ static int gfar_close(struct net_device *dev)
disable_napi(priv);
- skb_queue_purge(&priv->rx_recycle);
cancel_work_sync(&priv->reset_task);
stop_gfar(dev);
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index 24724b4ad709..07d8e5b634f3 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -71,6 +71,7 @@ static struct zorro_device_id hydra_zorro_tbl[] __devinitdata = {
{ ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, hydra_zorro_tbl);
static struct zorro_driver hydra_driver = {
.name = "hydra",
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index fc5938ba3d78..a527e37728cd 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -88,6 +88,11 @@ config LSI_ET1011C_PHY
---help---
Supports the LSI ET1011C PHY.
+config MICREL_PHY
+ tristate "Driver for Micrel PHYs"
+ ---help---
+ Supports the KSZ9021, VSC8201, KS8001 PHYs.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1342585af381..13bebab65d02 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -20,4 +20,5 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
+obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
new file mode 100644
index 000000000000..e67691dca4ab
--- /dev/null
+++ b/drivers/net/phy/micrel.c
@@ -0,0 +1,105 @@
+/*
+ * drivers/net/phy/micrel.c
+ *
+ * Driver for Micrel PHYs
+ *
+ * Author: David J. Choi
+ *
+ * Copyright (c) 2010 Micrel, Inc.
+ *
+ * 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.
+ *
+ * Support : ksz9021 , vsc8201, ks8001
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define PHY_ID_KSZ9021 0x00221611
+#define PHY_ID_VSC8201 0x000FC413
+#define PHY_ID_KS8001 0x0022161A
+
+
+static int kszphy_config_init(struct phy_device *phydev)
+{
+ return 0;
+}
+
+
+static struct phy_driver ks8001_driver = {
+ .phy_id = PHY_ID_KS8001,
+ .name = "Micrel KS8001",
+ .phy_id_mask = 0x00fffff0,
+ .features = PHY_BASIC_FEATURES,
+ .flags = PHY_POLL,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver vsc8201_driver = {
+ .phy_id = PHY_ID_VSC8201,
+ .name = "Micrel VSC8201",
+ .phy_id_mask = 0x00fffff0,
+ .features = PHY_BASIC_FEATURES,
+ .flags = PHY_POLL,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static struct phy_driver ksz9021_driver = {
+ .phy_id = PHY_ID_KSZ9021,
+ .phy_id_mask = 0x000fff10,
+ .name = "Micrel KSZ9021 Gigabit PHY",
+ .features = PHY_GBIT_FEATURES | SUPPORTED_Pause,
+ .flags = PHY_POLL,
+ .config_init = kszphy_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE, },
+};
+
+static int __init ksphy_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&ks8001_driver);
+ if (ret)
+ goto err1;
+ ret = phy_driver_register(&vsc8201_driver);
+ if (ret)
+ goto err2;
+
+ ret = phy_driver_register(&ksz9021_driver);
+ if (ret)
+ goto err3;
+ return 0;
+
+err3:
+ phy_driver_unregister(&vsc8201_driver);
+err2:
+ phy_driver_unregister(&ks8001_driver);
+err1:
+ return ret;
+}
+
+static void __exit ksphy_exit(void)
+{
+ phy_driver_unregister(&ks8001_driver);
+ phy_driver_unregister(&vsc8201_driver);
+ phy_driver_unregister(&ksz9021_driver);
+}
+
+module_init(ksphy_init);
+module_exit(ksphy_exit);
+
+MODULE_DESCRIPTION("Micrel PHY driver");
+MODULE_AUTHOR("David J. Choi");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 6e281bc825e5..8518a2e58e53 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -405,6 +405,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
DECLARE_WAITQUEUE(wait, current);
ssize_t ret;
struct sk_buff *skb = NULL;
+ struct iovec iov;
ret = count;
@@ -448,7 +449,9 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
if (skb->len > count)
goto outf;
ret = -EFAULT;
- if (copy_to_user(buf, skb->data, skb->len))
+ iov.iov_base = buf;
+ iov.iov_len = count;
+ if (skb_copy_datagram_iovec(skb, 0, &iov, skb->len))
goto outf;
ret = skb->len;
@@ -1567,13 +1570,22 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
struct channel *pch = chan->ppp;
int proto;
- if (!pch || skb->len == 0) {
+ if (!pch) {
kfree_skb(skb);
return;
}
- proto = PPP_PROTO(skb);
read_lock_bh(&pch->upl);
+ if (!pskb_may_pull(skb, 2)) {
+ kfree_skb(skb);
+ if (pch->ppp) {
+ ++pch->ppp->dev->stats.rx_length_errors;
+ ppp_receive_error(pch->ppp);
+ }
+ goto done;
+ }
+
+ proto = PPP_PROTO(skb);
if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
@@ -1585,6 +1597,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
} else {
ppp_do_recv(pch->ppp, skb, pch);
}
+
+done:
read_unlock_bh(&pch->upl);
}
@@ -1617,7 +1631,8 @@ ppp_input_error(struct ppp_channel *chan, int code)
static void
ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
- if (pskb_may_pull(skb, 2)) {
+ /* note: a 0-length skb is used as an error indication */
+ if (skb->len > 0) {
#ifdef CONFIG_PPP_MULTILINK
/* XXX do channel-level decompression here */
if (PPP_PROTO(skb) == PPP_MP)
@@ -1625,15 +1640,10 @@ ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
else
#endif /* CONFIG_PPP_MULTILINK */
ppp_receive_nonmp_frame(ppp, skb);
- return;
+ } else {
+ kfree_skb(skb);
+ ppp_receive_error(ppp);
}
-
- if (skb->len > 0)
- /* note: a 0-length skb is used as an error indication */
- ++ppp->dev->stats.rx_length_errors;
-
- kfree_skb(skb);
- ppp_receive_error(ppp);
}
static void
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 4748c21eb72e..dd8106ff35aa 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1042,14 +1042,14 @@ static void rtl8169_vlan_rx_register(struct net_device *dev,
}
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
- struct sk_buff *skb)
+ struct sk_buff *skb, int polling)
{
u32 opts2 = le32_to_cpu(desc->opts2);
struct vlan_group *vlgrp = tp->vlgrp;
int ret;
if (vlgrp && (opts2 & RxVlanTag)) {
- vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
+ __vlan_hwaccel_rx(skb, vlgrp, swab16(opts2 & 0xffff), polling);
ret = 0;
} else
ret = -1;
@@ -1066,7 +1066,7 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
}
static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
- struct sk_buff *skb)
+ struct sk_buff *skb, int polling)
{
return -1;
}
@@ -4445,12 +4445,20 @@ out:
return done;
}
+/*
+ * Warning : rtl8169_rx_interrupt() might be called :
+ * 1) from NAPI (softirq) context
+ * (polling = 1 : we should call netif_receive_skb())
+ * 2) from process context (rtl8169_reset_task())
+ * (polling = 0 : we must call netif_rx() instead)
+ */
static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp,
void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
+ int polling = (budget != ~(u32)0) ? 1 : 0;
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
@@ -4512,8 +4520,12 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
- if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
- netif_receive_skb(skb);
+ if (rtl8169_rx_vlan_skb(tp, desc, skb, polling) < 0) {
+ if (likely(polling))
+ netif_receive_skb(skb);
+ else
+ netif_rx(skb);
+ }
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 9944e5d662c0..04efc0c1bda9 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2353,17 +2353,36 @@ static int sbmac_init(struct platform_device *pldev, long long base)
sc->mii_bus = mdiobus_alloc();
if (sc->mii_bus == NULL) {
- sbmac_uninitctx(sc);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto uninit_ctx;
}
+ sc->mii_bus->name = sbmac_mdio_string;
+ snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
+ sc->mii_bus->priv = sc;
+ sc->mii_bus->read = sbmac_mii_read;
+ sc->mii_bus->write = sbmac_mii_write;
+ sc->mii_bus->irq = sc->phy_irq;
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ sc->mii_bus->irq[i] = SBMAC_PHY_INT;
+
+ sc->mii_bus->parent = &pldev->dev;
+ /*
+ * Probe PHY address
+ */
+ err = mdiobus_register(sc->mii_bus);
+ if (err) {
+ printk(KERN_ERR "%s: unable to register MDIO bus\n",
+ dev->name);
+ goto free_mdio;
+ }
+ dev_set_drvdata(&pldev->dev, sc->mii_bus);
+
err = register_netdev(dev);
if (err) {
printk(KERN_ERR "%s.%d: unable to register netdev\n",
sbmac_string, idx);
- mdiobus_free(sc->mii_bus);
- sbmac_uninitctx(sc);
- return err;
+ goto unreg_mdio;
}
pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name);
@@ -2379,19 +2398,15 @@ static int sbmac_init(struct platform_device *pldev, long long base)
pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %pM\n",
dev->name, base, eaddr);
- sc->mii_bus->name = sbmac_mdio_string;
- snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx);
- sc->mii_bus->priv = sc;
- sc->mii_bus->read = sbmac_mii_read;
- sc->mii_bus->write = sbmac_mii_write;
- sc->mii_bus->irq = sc->phy_irq;
- for (i = 0; i < PHY_MAX_ADDR; ++i)
- sc->mii_bus->irq[i] = SBMAC_PHY_INT;
-
- sc->mii_bus->parent = &pldev->dev;
- dev_set_drvdata(&pldev->dev, sc->mii_bus);
-
return 0;
+unreg_mdio:
+ mdiobus_unregister(sc->mii_bus);
+ dev_set_drvdata(&pldev->dev, NULL);
+free_mdio:
+ mdiobus_free(sc->mii_bus);
+uninit_ctx:
+ sbmac_uninitctx(sc);
+ return err;
}
@@ -2417,16 +2432,6 @@ static int sbmac_open(struct net_device *dev)
goto out_err;
}
- /*
- * Probe PHY address
- */
- err = mdiobus_register(sc->mii_bus);
- if (err) {
- printk(KERN_ERR "%s: unable to register MDIO bus\n",
- dev->name);
- goto out_unirq;
- }
-
sc->sbm_speed = sbmac_speed_none;
sc->sbm_duplex = sbmac_duplex_none;
sc->sbm_fc = sbmac_fc_none;
@@ -2457,11 +2462,7 @@ static int sbmac_open(struct net_device *dev)
return 0;
out_unregister:
- mdiobus_unregister(sc->mii_bus);
-
-out_unirq:
free_irq(dev->irq, dev);
-
out_err:
return err;
}
@@ -2650,9 +2651,6 @@ static int sbmac_close(struct net_device *dev)
phy_disconnect(sc->phy_dev);
sc->phy_dev = NULL;
-
- mdiobus_unregister(sc->mii_bus);
-
free_irq(dev->irq, dev);
sbdma_emptyring(&(sc->sbm_txdma));
@@ -2760,6 +2758,7 @@ static int __exit sbmac_remove(struct platform_device *pldev)
unregister_netdev(dev);
sbmac_uninitctx(sc);
+ mdiobus_unregister(sc->mii_bus);
mdiobus_free(sc->mii_bus);
iounmap(sc->sbm_base);
free_netdev(dev);
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 5d58abc224f4..d7b7018a1de1 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -400,7 +400,6 @@ config USB_IPHETH
config USB_SIERRA_NET
tristate "USB-to-WWAN Driver for Sierra Wireless modems"
depends on USB_USBNET
- default y
help
Choose this option if you have a Sierra Wireless USB-to-WWAN device.
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 04b281002a76..5dfed9297b22 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -240,7 +240,7 @@ static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, __le16 valu
goto out;
dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg);
- dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14);
+ dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1a : 0x12);
for (i = 0; i < DM_TIMEOUT; i++) {
u8 tmp;
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index a44f9e0ea098..f1942d69a0d5 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -789,6 +789,9 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
/* prepare sync message from template */
memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg));
+ /* initiate the sync sequence */
+ sierra_net_dosync(dev);
+
return 0;
}
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index f9f0730b53d5..5ec542dd5b50 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -187,7 +187,6 @@ tx_drop:
return NETDEV_TX_OK;
rx_drop:
- kfree_skb(skb);
rcv_stats->rx_dropped++;
return NETDEV_TX_OK;
}
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 99a6da464bd3..e1c2fcaa8bed 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -727,12 +727,16 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
{
struct device *parent = aru->udev->dev.parent;
+ complete(&aru->firmware_loading_complete);
+
/* unbind anything failed */
if (parent)
down(&parent->sem);
device_release_driver(&aru->udev->dev);
if (parent)
up(&parent->sem);
+
+ usb_put_dev(aru->udev);
}
static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
@@ -761,6 +765,8 @@ static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
if (err)
goto err_unrx;
+ complete(&aru->firmware_loading_complete);
+ usb_put_dev(aru->udev);
return;
err_unrx:
@@ -858,6 +864,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
init_usb_anchor(&aru->tx_pending);
init_usb_anchor(&aru->tx_submitted);
init_completion(&aru->cmd_wait);
+ init_completion(&aru->firmware_loading_complete);
spin_lock_init(&aru->tx_urb_lock);
aru->tx_pending_urbs = 0;
@@ -877,6 +884,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
if (err)
goto err_freehw;
+ usb_get_dev(aru->udev);
return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
&aru->udev->dev, GFP_KERNEL, aru,
ar9170_usb_firmware_step2);
@@ -896,6 +904,9 @@ static void ar9170_usb_disconnect(struct usb_interface *intf)
return;
aru->common.state = AR9170_IDLE;
+
+ wait_for_completion(&aru->firmware_loading_complete);
+
ar9170_unregister(&aru->common);
ar9170_usb_cancel_urbs(aru);
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
index a2ce3b169ceb..919b06046eb3 100644
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ b/drivers/net/wireless/ath/ar9170/usb.h
@@ -71,6 +71,7 @@ struct ar9170_usb {
unsigned int tx_pending_urbs;
struct completion cmd_wait;
+ struct completion firmware_loading_complete;
int readlen;
u8 *readbuf;
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 6383d9f8c9b3..f4e59ae07f8e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2621,7 +2621,9 @@ struct iwl_ssid_ie {
#define PROBE_OPTION_MAX_3945 4
#define PROBE_OPTION_MAX 20
#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF)
-#define IWL_GOOD_CRC_TH cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_DISABLED 0
+#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
+#define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff)
#define IWL_MAX_SCAN_SIZE 1024
#define IWL_MAX_CMD_SIZE 4096
#define IWL_MAX_PROBE_REQUEST 200
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 12e455a4b90e..741e65ec8301 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -813,16 +813,29 @@ static void iwl_bg_request_scan(struct work_struct *data)
rate = IWL_RATE_1M_PLCP;
rate_flags = RATE_MCS_CCK_MSK;
}
- scan->good_CRC_th = 0;
+ scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
} else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
band = IEEE80211_BAND_5GHZ;
rate = IWL_RATE_6M_PLCP;
/*
- * If active scaning is requested but a certain channel
- * is marked passive, we can do active scanning if we
- * detect transmissions.
+ * If active scanning is requested but a certain channel is
+ * marked passive, we can do active scanning if we detect
+ * transmissions.
+ *
+ * There is an issue with some firmware versions that triggers
+ * a sysassert on a "good CRC threshold" of zero (== disabled),
+ * on a radar channel even though this means that we should NOT
+ * send probes.
+ *
+ * The "good CRC threshold" is the number of frames that we
+ * need to receive during our dwell time on a channel before
+ * sending out probes -- setting this to a huge value will
+ * mean we never reach it, but at the same time work around
+ * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+ * here instead of IWL_GOOD_CRC_TH_DISABLED.
*/
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_NEVER;
/* Force use of chains B and C (0x6) for scan Rx for 4965
* Avoid A (0x1) because of its off-channel reception on A-band.
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index b55e4f39a9e1..b74a56c48d26 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2967,7 +2967,8 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
* is marked passive, we can do active scanning if we
* detect transmissions.
*/
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH : 0;
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_DISABLED;
band = IEEE80211_BAND_5GHZ;
} else {
IWL_WARN(priv, "Invalid scan band count\n");
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 269fda362836..c24067f1a0cb 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -246,7 +246,7 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
u32 idx, i;
i = (*index) % ring_limit;
- (*index) = idx = le32_to_cpu(ring_control->device_idx[1]);
+ (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
idx %= ring_limit;
while (i != idx) {
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index 81c753a617ab..9548cbb5012a 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -102,6 +102,7 @@ static struct zorro_device_id zorro8390_zorro_tbl[] __devinitdata = {
{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, zorro8390_zorro_tbl);
static struct zorro_driver zorro8390_driver = {
.name = "zorro8390",
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 166b67ea622f..219f79e2210a 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -30,23 +30,7 @@
#define OP_BUFFER_FLAGS 0
-/*
- * Read and write access is using spin locking. Thus, writing to the
- * buffer by NMI handler (x86) could occur also during critical
- * sections when reading the buffer. To avoid this, there are 2
- * buffers for independent read and write access. Read access is in
- * process context only, write access only in the NMI handler. If the
- * read buffer runs empty, both buffers are swapped atomically. There
- * is potentially a small window during swapping where the buffers are
- * disabled and samples could be lost.
- *
- * Using 2 buffers is a little bit overhead, but the solution is clear
- * and does not require changes in the ring buffer implementation. It
- * can be changed to a single buffer solution when the ring buffer
- * access is implemented as non-locking atomic code.
- */
-static struct ring_buffer *op_ring_buffer_read;
-static struct ring_buffer *op_ring_buffer_write;
+static struct ring_buffer *op_ring_buffer;
DEFINE_PER_CPU(struct oprofile_cpu_buffer, op_cpu_buffer);
static void wq_sync_buffer(struct work_struct *work);
@@ -68,12 +52,9 @@ void oprofile_cpu_buffer_inc_smpl_lost(void)
void free_cpu_buffers(void)
{
- if (op_ring_buffer_read)
- ring_buffer_free(op_ring_buffer_read);
- op_ring_buffer_read = NULL;
- if (op_ring_buffer_write)
- ring_buffer_free(op_ring_buffer_write);
- op_ring_buffer_write = NULL;
+ if (op_ring_buffer)
+ ring_buffer_free(op_ring_buffer);
+ op_ring_buffer = NULL;
}
#define RB_EVENT_HDR_SIZE 4
@@ -86,11 +67,8 @@ int alloc_cpu_buffers(void)
unsigned long byte_size = buffer_size * (sizeof(struct op_sample) +
RB_EVENT_HDR_SIZE);
- op_ring_buffer_read = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS);
- if (!op_ring_buffer_read)
- goto fail;
- op_ring_buffer_write = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS);
- if (!op_ring_buffer_write)
+ op_ring_buffer = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS);
+ if (!op_ring_buffer)
goto fail;
for_each_possible_cpu(i) {
@@ -162,16 +140,11 @@ struct op_sample
*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size)
{
entry->event = ring_buffer_lock_reserve
- (op_ring_buffer_write, sizeof(struct op_sample) +
+ (op_ring_buffer, sizeof(struct op_sample) +
size * sizeof(entry->sample->data[0]));
- if (entry->event)
- entry->sample = ring_buffer_event_data(entry->event);
- else
- entry->sample = NULL;
-
- if (!entry->sample)
+ if (!entry->event)
return NULL;
-
+ entry->sample = ring_buffer_event_data(entry->event);
entry->size = size;
entry->data = entry->sample->data;
@@ -180,25 +153,16 @@ struct op_sample
int op_cpu_buffer_write_commit(struct op_entry *entry)
{
- return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event);
+ return ring_buffer_unlock_commit(op_ring_buffer, entry->event);
}
struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu)
{
struct ring_buffer_event *e;
- e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
- if (e)
- goto event;
- if (ring_buffer_swap_cpu(op_ring_buffer_read,
- op_ring_buffer_write,
- cpu))
+ e = ring_buffer_consume(op_ring_buffer, cpu, NULL, NULL);
+ if (!e)
return NULL;
- e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
- if (e)
- goto event;
- return NULL;
-event:
entry->event = e;
entry->sample = ring_buffer_event_data(e);
entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample))
@@ -209,8 +173,7 @@ event:
unsigned long op_cpu_buffer_entries(int cpu)
{
- return ring_buffer_entries_cpu(op_ring_buffer_read, cpu)
- + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
+ return ring_buffer_entries_cpu(op_ring_buffer, cpu);
}
static int
@@ -356,8 +319,16 @@ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
{
- int is_kernel = !user_mode(regs);
- unsigned long pc = profile_pc(regs);
+ int is_kernel;
+ unsigned long pc;
+
+ if (likely(regs)) {
+ is_kernel = !user_mode(regs);
+ pc = profile_pc(regs);
+ } else {
+ is_kernel = 0; /* This value will not be used */
+ pc = ESCAPE_CODE; /* as this causes an early return. */
+ }
__oprofile_add_ext_sample(pc, regs, event, is_kernel);
}
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index dc8a0428260d..b336cd9ee7a1 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -253,22 +253,26 @@ static int __init oprofile_init(void)
int err;
err = oprofile_arch_init(&oprofile_ops);
-
if (err < 0 || timer) {
printk(KERN_INFO "oprofile: using timer interrupt.\n");
- oprofile_timer_init(&oprofile_ops);
+ err = oprofile_timer_init(&oprofile_ops);
+ if (err)
+ goto out_arch;
}
-
err = oprofilefs_register();
if (err)
- oprofile_arch_exit();
+ goto out_arch;
+ return 0;
+out_arch:
+ oprofile_arch_exit();
return err;
}
static void __exit oprofile_exit(void)
{
+ oprofile_timer_exit();
oprofilefs_unregister();
oprofile_arch_exit();
}
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index cb92f5c98c1a..47e12cb4ee8b 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -34,7 +34,8 @@ struct super_block;
struct dentry;
void oprofile_create_files(struct super_block *sb, struct dentry *root);
-void oprofile_timer_init(struct oprofile_operations *ops);
+int oprofile_timer_init(struct oprofile_operations *ops);
+void oprofile_timer_exit(void);
int oprofile_set_backtrace(unsigned long depth);
int oprofile_set_timeout(unsigned long time);
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c
index 333f915568c7..dc0ae4d14dff 100644
--- a/drivers/oprofile/timer_int.c
+++ b/drivers/oprofile/timer_int.c
@@ -13,34 +13,94 @@
#include <linux/oprofile.h>
#include <linux/profile.h>
#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/hrtimer.h>
+#include <asm/irq_regs.h>
#include <asm/ptrace.h>
#include "oprof.h"
-static int timer_notify(struct pt_regs *regs)
+static DEFINE_PER_CPU(struct hrtimer, oprofile_hrtimer);
+
+static enum hrtimer_restart oprofile_hrtimer_notify(struct hrtimer *hrtimer)
+{
+ oprofile_add_sample(get_irq_regs(), 0);
+ hrtimer_forward_now(hrtimer, ns_to_ktime(TICK_NSEC));
+ return HRTIMER_RESTART;
+}
+
+static void __oprofile_hrtimer_start(void *unused)
+{
+ struct hrtimer *hrtimer = &__get_cpu_var(oprofile_hrtimer);
+
+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer->function = oprofile_hrtimer_notify;
+
+ hrtimer_start(hrtimer, ns_to_ktime(TICK_NSEC),
+ HRTIMER_MODE_REL_PINNED);
+}
+
+static int oprofile_hrtimer_start(void)
{
- oprofile_add_sample(regs, 0);
+ on_each_cpu(__oprofile_hrtimer_start, NULL, 1);
return 0;
}
-static int timer_start(void)
+static void __oprofile_hrtimer_stop(int cpu)
{
- return register_timer_hook(timer_notify);
+ struct hrtimer *hrtimer = &per_cpu(oprofile_hrtimer, cpu);
+
+ hrtimer_cancel(hrtimer);
}
+static void oprofile_hrtimer_stop(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ __oprofile_hrtimer_stop(cpu);
+}
-static void timer_stop(void)
+static int __cpuinit oprofile_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
{
- unregister_timer_hook(timer_notify);
+ long cpu = (long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ smp_call_function_single(cpu, __oprofile_hrtimer_start,
+ NULL, 1);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ __oprofile_hrtimer_stop(cpu);
+ break;
+ }
+ return NOTIFY_OK;
}
+static struct notifier_block __refdata oprofile_cpu_notifier = {
+ .notifier_call = oprofile_cpu_notify,
+};
-void __init oprofile_timer_init(struct oprofile_operations *ops)
+int __init oprofile_timer_init(struct oprofile_operations *ops)
{
+ int rc;
+
+ rc = register_hotcpu_notifier(&oprofile_cpu_notifier);
+ if (rc)
+ return rc;
ops->create_files = NULL;
ops->setup = NULL;
ops->shutdown = NULL;
- ops->start = timer_start;
- ops->stop = timer_stop;
+ ops->start = oprofile_hrtimer_start;
+ ops->stop = oprofile_hrtimer_stop;
ops->cpu_type = "timer";
+ return 0;
+}
+
+void __exit oprofile_timer_exit(void)
+{
+ unregister_hotcpu_notifier(&oprofile_cpu_notifier);
}
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 417312528ddf..371dc564e2e4 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -3626,14 +3626,15 @@ static void intel_iommu_detach_device(struct iommu_domain *domain,
domain_remove_one_dev_info(dmar_domain, pdev);
}
-static int intel_iommu_map_range(struct iommu_domain *domain,
- unsigned long iova, phys_addr_t hpa,
- size_t size, int iommu_prot)
+static int intel_iommu_map(struct iommu_domain *domain,
+ unsigned long iova, phys_addr_t hpa,
+ int gfp_order, int iommu_prot)
{
struct dmar_domain *dmar_domain = domain->priv;
u64 max_addr;
int addr_width;
int prot = 0;
+ size_t size;
int ret;
if (iommu_prot & IOMMU_READ)
@@ -3643,6 +3644,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
prot |= DMA_PTE_SNP;
+ size = PAGE_SIZE << gfp_order;
max_addr = iova + size;
if (dmar_domain->max_addr < max_addr) {
int min_agaw;
@@ -3669,19 +3671,19 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
return ret;
}
-static void intel_iommu_unmap_range(struct iommu_domain *domain,
- unsigned long iova, size_t size)
+static int intel_iommu_unmap(struct iommu_domain *domain,
+ unsigned long iova, int gfp_order)
{
struct dmar_domain *dmar_domain = domain->priv;
-
- if (!size)
- return;
+ size_t size = PAGE_SIZE << gfp_order;
dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
(iova + size - 1) >> VTD_PAGE_SHIFT);
if (dmar_domain->max_addr == iova + size)
dmar_domain->max_addr = iova;
+
+ return gfp_order;
}
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -3714,8 +3716,8 @@ static struct iommu_ops intel_iommu_ops = {
.domain_destroy = intel_iommu_domain_destroy,
.attach_dev = intel_iommu_attach_device,
.detach_dev = intel_iommu_detach_device,
- .map = intel_iommu_map_range,
- .unmap = intel_iommu_unmap_range,
+ .map = intel_iommu_map,
+ .unmap = intel_iommu_unmap,
.iova_to_phys = intel_iommu_iova_to_phys,
.domain_has_cap = intel_iommu_domain_has_cap,
};
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4fe36d2e1049..19b111383f62 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -838,65 +838,11 @@ static void pci_bus_dump_resources(struct pci_bus *bus)
}
}
-static int __init pci_bus_get_depth(struct pci_bus *bus)
-{
- int depth = 0;
- struct pci_dev *dev;
-
- list_for_each_entry(dev, &bus->devices, bus_list) {
- int ret;
- struct pci_bus *b = dev->subordinate;
- if (!b)
- continue;
-
- ret = pci_bus_get_depth(b);
- if (ret + 1 > depth)
- depth = ret + 1;
- }
-
- return depth;
-}
-static int __init pci_get_max_depth(void)
-{
- int depth = 0;
- struct pci_bus *bus;
-
- list_for_each_entry(bus, &pci_root_buses, node) {
- int ret;
-
- ret = pci_bus_get_depth(bus);
- if (ret > depth)
- depth = ret;
- }
-
- return depth;
-}
-
-/*
- * first try will not touch pci bridge res
- * second and later try will clear small leaf bridge res
- * will stop till to the max deepth if can not find good one
- */
void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
- int tried_times = 0;
- enum release_type rel_type = leaf_only;
- struct resource_list_x head, *list;
- unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
- IORESOURCE_PREFETCH;
- unsigned long failed_type;
- int max_depth = pci_get_max_depth();
- int pci_try_num;
- head.next = NULL;
-
- pci_try_num = max_depth + 1;
- printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
- max_depth, pci_try_num);
-
-again:
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) {
@@ -904,65 +850,9 @@ again:
}
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node) {
- __pci_bus_assign_resources(bus, &head);
- }
- tried_times++;
-
- /* any device complain? */
- if (!head.next)
- goto enable_and_dump;
- failed_type = 0;
- for (list = head.next; list;) {
- failed_type |= list->flags;
- list = list->next;
- }
- /*
- * io port are tight, don't try extra
- * or if reach the limit, don't want to try more
- */
- failed_type &= type_mask;
- if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
- free_failed_list(&head);
- goto enable_and_dump;
- }
-
- printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
- tried_times + 1);
-
- /* third times and later will not check if it is leaf */
- if ((tried_times + 1) > 2)
- rel_type = whole_subtree;
-
- /*
- * Try to release leaf bridge's resources that doesn't fit resource of
- * child device under that bridge
- */
- for (list = head.next; list;) {
- bus = list->dev->bus;
- pci_bus_release_bridge_resources(bus, list->flags & type_mask,
- rel_type);
- list = list->next;
- }
- /* restore size and flags */
- for (list = head.next; list;) {
- struct resource *res = list->res;
-
- res->start = list->start;
- res->end = list->end;
- res->flags = list->flags;
- if (list->dev->subordinate)
- res->flags = 0;
-
- list = list->next;
- }
- free_failed_list(&head);
-
- goto again;
-
-enable_and_dump:
- /* Depth last, update the hardware. */
- list_for_each_entry(bus, &pci_root_buses, node)
+ pci_bus_assign_resources(bus);
pci_enable_bridges(bus);
+ }
/* dump the resource on buses */
list_for_each_entry(bus, &pci_root_buses, node) {
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index d189e4743e69..a44733d44ca1 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -234,7 +234,8 @@ config PCMCIA_PXA2XX
depends on ARM && ARCH_PXA && PCMCIA
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
- || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2)
+ || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
+ || MACH_VPAC270)
select PCMCIA_SOC_COMMON
help
Say Y here to include support for the PXA2xx PCMCIA controller
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 381b031d9d75..4dae3613c458 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -66,6 +66,7 @@ pxa2xx-obj-$(CONFIG_MACH_PALMTC) += pxa2xx_palmtc.o
pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
+pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 75ed866e6953..c3383750e333 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -671,20 +671,22 @@ static int pccardd(void *__skt)
socket_remove(skt);
if (sysfs_events & PCMCIA_UEVENT_INSERT)
socket_insert(skt);
- if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
- !(skt->state & SOCKET_CARDBUS)) {
- ret = socket_resume(skt);
- if (!ret && skt->callback)
- skt->callback->resume(skt);
- }
if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
!(skt->state & SOCKET_CARDBUS)) {
if (skt->callback)
ret = skt->callback->suspend(skt);
else
ret = 0;
- if (!ret)
+ if (!ret) {
socket_suspend(skt);
+ msleep(100);
+ }
+ }
+ if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
+ !(skt->state & SOCKET_CARDBUS)) {
+ ret = socket_resume(skt);
+ if (!ret && skt->callback)
+ skt->callback->resume(skt);
}
if ((sysfs_events & PCMCIA_UEVENT_REQUERY) &&
!(skt->state & SOCKET_CARDBUS)) {
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 508f94a2a78d..041eee43fd8d 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1283,6 +1283,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
destroy_cis_cache(skt);
kfree(skt->fake_cis);
skt->fake_cis = NULL;
+ s->functions = 0;
mutex_unlock(&s->ops_mutex);
/* now, add the new card */
ds_event(skt, CS_EVENT_CARD_INSERTION,
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 104e73d5d86c..7631faa0cadd 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -711,7 +711,7 @@ static int ds_open(struct inode *inode, struct file *file)
warning_printed = 1;
}
- if (s->pcmcia_state.present)
+ if (atomic_read(&s->present))
queue_event(user, CS_EVENT_CARD_INSERTION);
out:
unlock_kernel();
@@ -770,9 +770,6 @@ static ssize_t ds_read(struct file *file, char __user *buf,
return -EIO;
s = user->socket;
- if (s->pcmcia_state.dead)
- return -EIO;
-
ret = wait_event_interruptible(s->queue, !queue_empty(user));
if (ret == 0)
ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
@@ -838,8 +835,6 @@ static int ds_ioctl(struct inode *inode, struct file *file,
return -EIO;
s = user->socket;
- if (s->pcmcia_state.dead)
- return -EIO;
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
if (size > sizeof(ds_ioctl_arg_t))
diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c
new file mode 100644
index 000000000000..55627eccee8e
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_vpac270.c
@@ -0,0 +1,229 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_vpac270.c
+ *
+ * Driver for Voipac PXA270 PCMCIA and CF sockets
+ *
+ * Copyright (C) 2010
+ * Marek Vasut <marek.vasut@gmail.com>
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/gpio.h>
+#include <mach/vpac270.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs cd_irqs[] = {
+ {
+ .sock = 0,
+ .irq = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD),
+ .str = "PCMCIA CD"
+ },
+ {
+ .sock = 1,
+ .irq = IRQ_GPIO(GPIO17_VPAC270_CF_CD),
+ .str = "CF CD"
+ },
+};
+
+static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ int ret;
+
+ if (skt->nr == 0) {
+ ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD");
+ if (ret)
+ goto err1;
+ ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD);
+ if (ret)
+ goto err2;
+
+ ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY");
+ if (ret)
+ goto err2;
+ ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY);
+ if (ret)
+ goto err3;
+
+ ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN");
+ if (ret)
+ goto err3;
+ ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0);
+ if (ret)
+ goto err4;
+
+ ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET");
+ if (ret)
+ goto err4;
+ ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0);
+ if (ret)
+ goto err5;
+
+ skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
+
+ return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
+
+err5:
+ gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
+err4:
+ gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
+err3:
+ gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
+err2:
+ gpio_free(GPIO84_VPAC270_PCMCIA_CD);
+err1:
+ return ret;
+
+ } else {
+ ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD");
+ if (ret)
+ goto err6;
+ ret = gpio_direction_input(GPIO17_VPAC270_CF_CD);
+ if (ret)
+ goto err7;
+
+ ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY");
+ if (ret)
+ goto err7;
+ ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY);
+ if (ret)
+ goto err8;
+
+ ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET");
+ if (ret)
+ goto err8;
+ ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0);
+ if (ret)
+ goto err9;
+
+ skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
+
+ return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
+
+err9:
+ gpio_free(GPIO16_VPAC270_CF_RESET);
+err8:
+ gpio_free(GPIO12_VPAC270_CF_RDY);
+err7:
+ gpio_free(GPIO17_VPAC270_CF_CD);
+err6:
+ return ret;
+
+ }
+}
+
+static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
+ gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
+ gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
+ gpio_free(GPIO84_VPAC270_PCMCIA_CD);
+ gpio_free(GPIO16_VPAC270_CF_RESET);
+ gpio_free(GPIO12_VPAC270_CF_RDY);
+ gpio_free(GPIO17_VPAC270_CF_CD);
+}
+
+static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ if (skt->nr == 0) {
+ state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
+ state->ready = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
+ } else {
+ state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
+ state->ready = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
+ }
+ state->bvd1 = 1;
+ state->bvd2 = 1;
+ state->wrprot = 0;
+ state->vs_3v = 1;
+ state->vs_Xv = 0;
+}
+
+static int
+vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ if (skt->nr == 0) {
+ gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
+ (state->flags & SS_RESET));
+ gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
+ !(state->Vcc == 33 || state->Vcc == 50));
+ } else {
+ gpio_set_value(GPIO16_VPAC270_CF_RESET,
+ (state->flags & SS_RESET));
+ }
+
+ return 0;
+}
+
+static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+static struct pcmcia_low_level vpac270_pcmcia_ops = {
+ .owner = THIS_MODULE,
+
+ .first = 0,
+ .nr = 2,
+
+ .hw_init = vpac270_pcmcia_hw_init,
+ .hw_shutdown = vpac270_pcmcia_hw_shutdown,
+
+ .socket_state = vpac270_pcmcia_socket_state,
+ .configure_socket = vpac270_pcmcia_configure_socket,
+
+ .socket_init = vpac270_pcmcia_socket_init,
+ .socket_suspend = vpac270_pcmcia_socket_suspend,
+};
+
+static struct platform_device *vpac270_pcmcia_device;
+
+static int __init vpac270_pcmcia_init(void)
+{
+ int ret;
+
+ if (!machine_is_vpac270())
+ return -ENODEV;
+
+ vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+ if (!vpac270_pcmcia_device)
+ return -ENOMEM;
+
+ ret = platform_device_add_data(vpac270_pcmcia_device,
+ &vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
+
+ if (!ret)
+ ret = platform_device_add(vpac270_pcmcia_device);
+
+ if (ret)
+ platform_device_put(vpac270_pcmcia_device);
+
+ return ret;
+}
+
+static void __exit vpac270_pcmcia_exit(void)
+{
+ platform_device_unregister(vpac270_pcmcia_device);
+}
+
+module_init(vpac270_pcmcia_init);
+module_exit(vpac270_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 35bb44af49b3..100e4d9372f1 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -274,26 +274,6 @@ static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev,
pnp_add_bus_resource(dev, start, end);
}
-static u64 addr_space_length(struct pnp_dev *dev, u64 min, u64 max, u64 len)
-{
- u64 max_len;
-
- max_len = max - min + 1;
- if (len <= max_len)
- return len;
-
- /*
- * Per 6.4.3.5, _LEN cannot exceed _MAX - _MIN + 1, but some BIOSes
- * don't do this correctly, e.g.,
- * https://bugzilla.kernel.org/show_bug.cgi?id=15480
- */
- dev_info(&dev->dev,
- "resource length %#llx doesn't fit in %#llx-%#llx, trimming\n",
- (unsigned long long) len, (unsigned long long) min,
- (unsigned long long) max);
- return max_len;
-}
-
static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
struct acpi_resource *res)
{
@@ -309,7 +289,8 @@ static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
return;
}
- len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
+ /* Windows apparently computes length rather than using _LEN */
+ len = p->maximum - p->minimum + 1;
window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
if (p->resource_type == ACPI_MEMORY_RANGE)
@@ -330,7 +311,8 @@ static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev,
int window;
u64 len;
- len = addr_space_length(dev, p->minimum, p->maximum, p->address_length);
+ /* Windows apparently computes length rather than using _LEN */
+ len = p->maximum - p->minimum + 1;
window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0;
if (p->resource_type == ACPI_MEMORY_RANGE)
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 2e54e6a23c72..e3446ab8b563 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -211,6 +211,8 @@ int pnp_check_port(struct pnp_dev *dev, struct resource *res)
if (tres->flags & IORESOURCE_IO) {
if (cannot_compare(tres->flags))
continue;
+ if (tres->flags & IORESOURCE_WINDOW)
+ continue;
tport = &tres->start;
tend = &tres->end;
if (ranged_conflict(port, end, tport, tend))
@@ -271,6 +273,8 @@ int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
if (tres->flags & IORESOURCE_MEM) {
if (cannot_compare(tres->flags))
continue;
+ if (tres->flags & IORESOURCE_WINDOW)
+ continue;
taddr = &tres->start;
tend = &tres->end;
if (ranged_conflict(addr, end, taddr, tend))
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index acf222f91f5a..0e86247d791e 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -37,6 +37,9 @@
*/
#define DASD_CHANQ_MAX_SIZE 4
+#define DASD_SLEEPON_START_TAG (void *) 1
+#define DASD_SLEEPON_END_TAG (void *) 2
+
/*
* SECTION: exported variables of dasd.c
*/
@@ -62,6 +65,7 @@ static void dasd_device_tasklet(struct dasd_device *);
static void dasd_block_tasklet(struct dasd_block *);
static void do_kick_device(struct work_struct *);
static void do_restore_device(struct work_struct *);
+static void do_reload_device(struct work_struct *);
static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
static void dasd_device_timeout(unsigned long);
static void dasd_block_timeout(unsigned long);
@@ -112,6 +116,7 @@ struct dasd_device *dasd_alloc_device(void)
device->timer.data = (unsigned long) device;
INIT_WORK(&device->kick_work, do_kick_device);
INIT_WORK(&device->restore_device, do_restore_device);
+ INIT_WORK(&device->reload_device, do_reload_device);
device->state = DASD_STATE_NEW;
device->target = DASD_STATE_NEW;
mutex_init(&device->state_mutex);
@@ -518,6 +523,26 @@ void dasd_kick_device(struct dasd_device *device)
}
/*
+ * dasd_reload_device will schedule a call do do_reload_device to the kernel
+ * event daemon.
+ */
+static void do_reload_device(struct work_struct *work)
+{
+ struct dasd_device *device = container_of(work, struct dasd_device,
+ reload_device);
+ device->discipline->reload(device);
+ dasd_put_device(device);
+}
+
+void dasd_reload_device(struct dasd_device *device)
+{
+ dasd_get_device(device);
+ /* queue call to dasd_reload_device to the kernel event daemon. */
+ schedule_work(&device->reload_device);
+}
+EXPORT_SYMBOL(dasd_reload_device);
+
+/*
* dasd_restore_device will schedule a call do do_restore_device to the kernel
* event daemon.
*/
@@ -1472,7 +1497,10 @@ void dasd_add_request_tail(struct dasd_ccw_req *cqr)
*/
static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data)
{
- wake_up((wait_queue_head_t *) data);
+ spin_lock_irq(get_ccwdev_lock(cqr->startdev->cdev));
+ cqr->callback_data = DASD_SLEEPON_END_TAG;
+ spin_unlock_irq(get_ccwdev_lock(cqr->startdev->cdev));
+ wake_up(&generic_waitq);
}
static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
@@ -1482,10 +1510,7 @@ static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr)
device = cqr->startdev;
spin_lock_irq(get_ccwdev_lock(device->cdev));
- rc = ((cqr->status == DASD_CQR_DONE ||
- cqr->status == DASD_CQR_NEED_ERP ||
- cqr->status == DASD_CQR_TERMINATED) &&
- list_empty(&cqr->devlist));
+ rc = (cqr->callback_data == DASD_SLEEPON_END_TAG);
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
}
@@ -1573,7 +1598,7 @@ static int _dasd_sleep_on(struct dasd_ccw_req *maincqr, int interruptible)
wait_event(generic_waitq, !(device->stopped));
cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &generic_waitq;
+ cqr->callback_data = DASD_SLEEPON_START_TAG;
dasd_add_request_tail(cqr);
if (interruptible) {
rc = wait_event_interruptible(
@@ -1652,7 +1677,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
}
cqr->callback = dasd_wakeup_cb;
- cqr->callback_data = (void *) &generic_waitq;
+ cqr->callback_data = DASD_SLEEPON_START_TAG;
cqr->status = DASD_CQR_QUEUED;
list_add(&cqr->devlist, &device->ccw_queue);
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 6632649dd6aa..85bfd8794856 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1418,9 +1418,29 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
struct dasd_ccw_req *erp)
{
struct dasd_ccw_req *cqr = erp->refers;
+ char *sense;
if (cqr->block &&
(cqr->block->base != cqr->startdev)) {
+
+ sense = dasd_get_sense(&erp->refers->irb);
+ /*
+ * dynamic pav may have changed base alias mapping
+ */
+ if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense
+ && (sense[0] == 0x10) && (sense[7] == 0x0F)
+ && (sense[8] == 0x67)) {
+ /*
+ * remove device from alias handling to prevent new
+ * requests from being scheduled on the
+ * wrong alias device
+ */
+ dasd_alias_remove_device(cqr->startdev);
+
+ /* schedule worker to reload device */
+ dasd_reload_device(cqr->startdev);
+ }
+
if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
DBF_DEV_EVENT(DBF_ERR, cqr->startdev,
"ERP on alias device for request %p,"
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 8c4814258e93..4155805dcdff 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -190,20 +190,21 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
struct alias_server *server, *newserver;
struct alias_lcu *lcu, *newlcu;
int is_lcu_known;
- struct dasd_uid *uid;
+ struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
- uid = &private->uid;
+
+ device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&aliastree.lock, flags);
is_lcu_known = 1;
- server = _find_server(uid);
+ server = _find_server(&uid);
if (!server) {
spin_unlock_irqrestore(&aliastree.lock, flags);
- newserver = _allocate_server(uid);
+ newserver = _allocate_server(&uid);
if (IS_ERR(newserver))
return PTR_ERR(newserver);
spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(uid);
+ server = _find_server(&uid);
if (!server) {
list_add(&newserver->server, &aliastree.serverlist);
server = newserver;
@@ -214,14 +215,14 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
}
}
- lcu = _find_lcu(server, uid);
+ lcu = _find_lcu(server, &uid);
if (!lcu) {
spin_unlock_irqrestore(&aliastree.lock, flags);
- newlcu = _allocate_lcu(uid);
+ newlcu = _allocate_lcu(&uid);
if (IS_ERR(newlcu))
return PTR_ERR(newlcu);
spin_lock_irqsave(&aliastree.lock, flags);
- lcu = _find_lcu(server, uid);
+ lcu = _find_lcu(server, &uid);
if (!lcu) {
list_add(&newlcu->lcu, &server->lculist);
lcu = newlcu;
@@ -256,20 +257,20 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device)
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
- struct dasd_uid *uid;
+ struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
- uid = &private->uid;
+ device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(uid);
+ server = _find_server(&uid);
if (server)
- lcu = _find_lcu(server, uid);
+ lcu = _find_lcu(server, &uid);
spin_unlock_irqrestore(&aliastree.lock, flags);
if (!lcu) {
DBF_EVENT_DEVID(DBF_ERR, device->cdev,
"could not find lcu for %04x %02x",
- uid->ssid, uid->real_unit_addr);
+ uid.ssid, uid.real_unit_addr);
WARN_ON(1);
return;
}
@@ -282,20 +283,20 @@ void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
- struct dasd_uid *uid;
+ struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
- uid = &private->uid;
+ device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
- server = _find_server(uid);
+ server = _find_server(&uid);
if (server)
- lcu = _find_lcu(server, uid);
+ lcu = _find_lcu(server, &uid);
spin_unlock_irqrestore(&aliastree.lock, flags);
if (!lcu) {
DBF_EVENT_DEVID(DBF_ERR, device->cdev,
"could not find lcu for %04x %02x",
- uid->ssid, uid->real_unit_addr);
+ uid.ssid, uid.real_unit_addr);
WARN_ON(1);
return;
}
@@ -314,9 +315,11 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
struct alias_lcu *lcu;
struct alias_server *server;
int was_pending;
+ struct dasd_uid uid;
private = (struct dasd_eckd_private *) device->private;
lcu = private->lcu;
+ device->discipline->get_uid(device, &uid);
spin_lock_irqsave(&lcu->lock, flags);
list_del_init(&device->alias_list);
/* make sure that the workers don't use this device */
@@ -353,7 +356,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
_schedule_lcu_update(lcu, NULL);
spin_unlock(&lcu->lock);
}
- server = _find_server(&private->uid);
+ server = _find_server(&uid);
if (server && list_empty(&server->lculist)) {
list_del(&server->server);
_free_server(server);
@@ -366,19 +369,30 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device)
* in the lcu is up to date and will update the device uid before
* adding it to a pav group.
*/
+
static int _add_device_to_lcu(struct alias_lcu *lcu,
- struct dasd_device *device)
+ struct dasd_device *device,
+ struct dasd_device *pos)
{
struct dasd_eckd_private *private;
struct alias_pav_group *group;
- struct dasd_uid *uid;
+ struct dasd_uid uid;
+ unsigned long flags;
private = (struct dasd_eckd_private *) device->private;
- uid = &private->uid;
- uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type;
- uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua;
- dasd_set_uid(device->cdev, &private->uid);
+
+ /* only lock if not already locked */
+ if (device != pos)
+ spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags,
+ CDEV_NESTED_SECOND);
+ private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type;
+ private->uid.base_unit_addr =
+ lcu->uac->unit[private->uid.real_unit_addr].base_ua;
+ uid = private->uid;
+
+ if (device != pos)
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
/* if we have no PAV anyway, we don't need to bother with PAV groups */
if (lcu->pav == NO_PAV) {
@@ -386,25 +400,25 @@ static int _add_device_to_lcu(struct alias_lcu *lcu,
return 0;
}
- group = _find_group(lcu, uid);
+ group = _find_group(lcu, &uid);
if (!group) {
group = kzalloc(sizeof(*group), GFP_ATOMIC);
if (!group)
return -ENOMEM;
- memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor));
- memcpy(group->uid.serial, uid->serial, sizeof(uid->serial));
- group->uid.ssid = uid->ssid;
- if (uid->type == UA_BASE_DEVICE)
- group->uid.base_unit_addr = uid->real_unit_addr;
+ memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor));
+ memcpy(group->uid.serial, uid.serial, sizeof(uid.serial));
+ group->uid.ssid = uid.ssid;
+ if (uid.type == UA_BASE_DEVICE)
+ group->uid.base_unit_addr = uid.real_unit_addr;
else
- group->uid.base_unit_addr = uid->base_unit_addr;
- memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit));
+ group->uid.base_unit_addr = uid.base_unit_addr;
+ memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit));
INIT_LIST_HEAD(&group->group);
INIT_LIST_HEAD(&group->baselist);
INIT_LIST_HEAD(&group->aliaslist);
list_add(&group->group, &lcu->grouplist);
}
- if (uid->type == UA_BASE_DEVICE)
+ if (uid.type == UA_BASE_DEVICE)
list_move(&device->alias_list, &group->baselist);
else
list_move(&device->alias_list, &group->aliaslist);
@@ -525,7 +539,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
if (rc)
return rc;
- spin_lock_irqsave(&lcu->lock, flags);
+ /* need to take cdev lock before lcu lock */
+ spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags,
+ CDEV_NESTED_FIRST);
+ spin_lock(&lcu->lock);
lcu->pav = NO_PAV;
for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) {
switch (lcu->uac->unit[i].ua_type) {
@@ -542,9 +559,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu)
list_for_each_entry_safe(device, tempdev, &lcu->active_devices,
alias_list) {
- _add_device_to_lcu(lcu, device);
+ _add_device_to_lcu(lcu, device, refdev);
}
- spin_unlock_irqrestore(&lcu->lock, flags);
+ spin_unlock(&lcu->lock);
+ spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags);
return 0;
}
@@ -628,9 +646,12 @@ int dasd_alias_add_device(struct dasd_device *device)
private = (struct dasd_eckd_private *) device->private;
lcu = private->lcu;
rc = 0;
- spin_lock_irqsave(&lcu->lock, flags);
+
+ /* need to take cdev lock before lcu lock */
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ spin_lock(&lcu->lock);
if (!(lcu->flags & UPDATE_PENDING)) {
- rc = _add_device_to_lcu(lcu, device);
+ rc = _add_device_to_lcu(lcu, device, device);
if (rc)
lcu->flags |= UPDATE_PENDING;
}
@@ -638,10 +659,19 @@ int dasd_alias_add_device(struct dasd_device *device)
list_move(&device->alias_list, &lcu->active_devices);
_schedule_lcu_update(lcu, device);
}
- spin_unlock_irqrestore(&lcu->lock, flags);
+ spin_unlock(&lcu->lock);
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
return rc;
}
+int dasd_alias_update_add_device(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private;
+ private = (struct dasd_eckd_private *) device->private;
+ private->lcu->flags |= UPDATE_PENDING;
+ return dasd_alias_add_device(device);
+}
+
int dasd_alias_remove_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
@@ -740,19 +770,30 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu)
struct alias_pav_group *pavgroup;
struct dasd_device *device;
struct dasd_eckd_private *private;
+ unsigned long flags;
/* active and inactive list can contain alias as well as base devices */
list_for_each_entry(device, &lcu->active_devices, alias_list) {
private = (struct dasd_eckd_private *) device->private;
- if (private->uid.type != UA_BASE_DEVICE)
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ if (private->uid.type != UA_BASE_DEVICE) {
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+ flags);
continue;
+ }
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_block_bh(device->block);
dasd_schedule_device_bh(device);
}
list_for_each_entry(device, &lcu->inactive_devices, alias_list) {
private = (struct dasd_eckd_private *) device->private;
- if (private->uid.type != UA_BASE_DEVICE)
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ if (private->uid.type != UA_BASE_DEVICE) {
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev),
+ flags);
continue;
+ }
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
dasd_schedule_block_bh(device->block);
dasd_schedule_device_bh(device);
}
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index eff9c812c5c2..34d51dd4c539 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -49,7 +49,6 @@ struct dasd_devmap {
unsigned int devindex;
unsigned short features;
struct dasd_device *device;
- struct dasd_uid uid;
};
/*
@@ -936,42 +935,46 @@ dasd_device_status_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL);
-static ssize_t
-dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dasd_alias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct dasd_devmap *devmap;
- int alias;
+ struct dasd_device *device;
+ struct dasd_uid uid;
- devmap = dasd_find_busid(dev_name(dev));
- spin_lock(&dasd_devmap_lock);
- if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
- spin_unlock(&dasd_devmap_lock);
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(device))
return sprintf(buf, "0\n");
+
+ if (device->discipline && device->discipline->get_uid &&
+ !device->discipline->get_uid(device, &uid)) {
+ if (uid.type == UA_BASE_PAV_ALIAS ||
+ uid.type == UA_HYPER_PAV_ALIAS)
+ return sprintf(buf, "1\n");
}
- if (devmap->uid.type == UA_BASE_PAV_ALIAS ||
- devmap->uid.type == UA_HYPER_PAV_ALIAS)
- alias = 1;
- else
- alias = 0;
- spin_unlock(&dasd_devmap_lock);
- return sprintf(buf, alias ? "1\n" : "0\n");
+ dasd_put_device(device);
+
+ return sprintf(buf, "0\n");
}
static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);
-static ssize_t
-dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t dasd_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct dasd_devmap *devmap;
+ struct dasd_device *device;
+ struct dasd_uid uid;
char *vendor;
- devmap = dasd_find_busid(dev_name(dev));
- spin_lock(&dasd_devmap_lock);
- if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)
- vendor = devmap->uid.vendor;
- else
- vendor = "";
- spin_unlock(&dasd_devmap_lock);
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ vendor = "";
+ if (IS_ERR(device))
+ return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
+
+ if (device->discipline && device->discipline->get_uid &&
+ !device->discipline->get_uid(device, &uid))
+ vendor = uid.vendor;
+
+ dasd_put_device(device);
return snprintf(buf, PAGE_SIZE, "%s\n", vendor);
}
@@ -985,48 +988,51 @@ static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);
static ssize_t
dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct dasd_devmap *devmap;
+ struct dasd_device *device;
+ struct dasd_uid uid;
char uid_string[UID_STRLEN];
char ua_string[3];
- struct dasd_uid *uid;
- devmap = dasd_find_busid(dev_name(dev));
- spin_lock(&dasd_devmap_lock);
- if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) {
- spin_unlock(&dasd_devmap_lock);
- return sprintf(buf, "\n");
- }
- uid = &devmap->uid;
- switch (uid->type) {
- case UA_BASE_DEVICE:
- sprintf(ua_string, "%02x", uid->real_unit_addr);
- break;
- case UA_BASE_PAV_ALIAS:
- sprintf(ua_string, "%02x", uid->base_unit_addr);
- break;
- case UA_HYPER_PAV_ALIAS:
- sprintf(ua_string, "xx");
- break;
- default:
- /* should not happen, treat like base device */
- sprintf(ua_string, "%02x", uid->real_unit_addr);
- break;
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ uid_string[0] = 0;
+ if (IS_ERR(device))
+ return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
+
+ if (device->discipline && device->discipline->get_uid &&
+ !device->discipline->get_uid(device, &uid)) {
+ switch (uid.type) {
+ case UA_BASE_DEVICE:
+ snprintf(ua_string, sizeof(ua_string), "%02x",
+ uid.real_unit_addr);
+ break;
+ case UA_BASE_PAV_ALIAS:
+ snprintf(ua_string, sizeof(ua_string), "%02x",
+ uid.base_unit_addr);
+ break;
+ case UA_HYPER_PAV_ALIAS:
+ snprintf(ua_string, sizeof(ua_string), "xx");
+ break;
+ default:
+ /* should not happen, treat like base device */
+ snprintf(ua_string, sizeof(ua_string), "%02x",
+ uid.real_unit_addr);
+ break;
+ }
+
+ if (strlen(uid.vduit) > 0)
+ snprintf(uid_string, sizeof(uid_string),
+ "%s.%s.%04x.%s.%s",
+ uid.vendor, uid.serial, uid.ssid, ua_string,
+ uid.vduit);
+ else
+ snprintf(uid_string, sizeof(uid_string),
+ "%s.%s.%04x.%s",
+ uid.vendor, uid.serial, uid.ssid, ua_string);
}
- if (strlen(uid->vduit) > 0)
- snprintf(uid_string, sizeof(uid_string),
- "%s.%s.%04x.%s.%s",
- uid->vendor, uid->serial,
- uid->ssid, ua_string,
- uid->vduit);
- else
- snprintf(uid_string, sizeof(uid_string),
- "%s.%s.%04x.%s",
- uid->vendor, uid->serial,
- uid->ssid, ua_string);
- spin_unlock(&dasd_devmap_lock);
+ dasd_put_device(device);
+
return snprintf(buf, PAGE_SIZE, "%s\n", uid_string);
}
-
static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);
/*
@@ -1094,50 +1100,6 @@ static struct attribute_group dasd_attr_group = {
};
/*
- * Return copy of the device unique identifier.
- */
-int
-dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
-{
- struct dasd_devmap *devmap;
-
- devmap = dasd_find_busid(dev_name(&cdev->dev));
- if (IS_ERR(devmap))
- return PTR_ERR(devmap);
- spin_lock(&dasd_devmap_lock);
- *uid = devmap->uid;
- spin_unlock(&dasd_devmap_lock);
- return 0;
-}
-EXPORT_SYMBOL_GPL(dasd_get_uid);
-
-/*
- * Register the given device unique identifier into devmap struct.
- * In addition check if the related storage server subsystem ID is already
- * contained in the dasd_server_ssid_list. If subsystem ID is not contained,
- * create new entry.
- * Return 0 if server was already in serverlist,
- * 1 if the server was added successful
- * <0 in case of error.
- */
-int
-dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
-{
- struct dasd_devmap *devmap;
-
- devmap = dasd_find_busid(dev_name(&cdev->dev));
- if (IS_ERR(devmap))
- return PTR_ERR(devmap);
-
- spin_lock(&dasd_devmap_lock);
- devmap->uid = *uid;
- spin_unlock(&dasd_devmap_lock);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(dasd_set_uid);
-
-/*
* Return value of the specified feature.
*/
int
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 0cb233116855..5b1cd8d6e971 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -692,18 +692,20 @@ dasd_eckd_cdl_reclen(int recid)
/*
* Generate device unique id that specifies the physical device.
*/
-static int dasd_eckd_generate_uid(struct dasd_device *device,
- struct dasd_uid *uid)
+static int dasd_eckd_generate_uid(struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ struct dasd_uid *uid;
int count;
+ unsigned long flags;
private = (struct dasd_eckd_private *) device->private;
if (!private)
return -ENODEV;
if (!private->ned || !private->gneq)
return -ENODEV;
-
+ uid = &private->uid;
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
memset(uid, 0, sizeof(struct dasd_uid));
memcpy(uid->vendor, private->ned->HDA_manufacturer,
sizeof(uid->vendor) - 1);
@@ -726,9 +728,25 @@ static int dasd_eckd_generate_uid(struct dasd_device *device,
private->vdsneq->uit[count]);
}
}
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
return 0;
}
+static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid)
+{
+ struct dasd_eckd_private *private;
+ unsigned long flags;
+
+ if (device->private) {
+ private = (struct dasd_eckd_private *)device->private;
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ *uid = private->uid;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+ return 0;
+ }
+ return -EINVAL;
+}
+
static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
void *rcd_buffer,
struct ciw *ciw, __u8 lpm)
@@ -1088,6 +1106,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
{
struct dasd_eckd_private *private;
struct dasd_block *block;
+ struct dasd_uid temp_uid;
int is_known, rc;
int readonly;
@@ -1124,13 +1143,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
if (rc)
goto out_err1;
- /* Generate device unique id and register in devmap */
- rc = dasd_eckd_generate_uid(device, &private->uid);
+ /* Generate device unique id */
+ rc = dasd_eckd_generate_uid(device);
if (rc)
goto out_err1;
- dasd_set_uid(device->cdev, &private->uid);
- if (private->uid.type == UA_BASE_DEVICE) {
+ dasd_eckd_get_uid(device, &temp_uid);
+ if (temp_uid.type == UA_BASE_DEVICE) {
block = dasd_alloc_block();
if (IS_ERR(block)) {
DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s",
@@ -1451,6 +1470,7 @@ static int dasd_eckd_ready_to_online(struct dasd_device *device)
static int dasd_eckd_online_to_ready(struct dasd_device *device)
{
+ cancel_work_sync(&device->reload_device);
return dasd_alias_remove_device(device);
};
@@ -1709,10 +1729,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device,
{
char mask;
char *sense = NULL;
+ struct dasd_eckd_private *private;
+ private = (struct dasd_eckd_private *) device->private;
/* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
if ((scsw_dstat(&irb->scsw) & mask) == mask) {
+ /* for alias only and not in offline processing*/
+ if (!device->block && private->lcu &&
+ !test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+ /*
+ * the state change could be caused by an alias
+ * reassignment remove device from alias handling
+ * to prevent new requests from being scheduled on
+ * the wrong alias device
+ */
+ dasd_alias_remove_device(device);
+
+ /* schedule worker to reload device */
+ dasd_reload_device(device);
+ }
+
dasd_generic_handle_state_change(device);
return;
}
@@ -3259,7 +3296,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
dasd_eckd_dump_sense_ccw(device, req, irb);
}
-int dasd_eckd_pm_freeze(struct dasd_device *device)
+static int dasd_eckd_pm_freeze(struct dasd_device *device)
{
/*
* the device should be disconnected from our LCU structure
@@ -3272,7 +3309,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device)
return 0;
}
-int dasd_eckd_restore_device(struct dasd_device *device)
+static int dasd_eckd_restore_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
struct dasd_eckd_characteristics temp_rdc_data;
@@ -3287,15 +3324,16 @@ int dasd_eckd_restore_device(struct dasd_device *device)
if (rc)
goto out_err;
- /* Generate device unique id and register in devmap */
- rc = dasd_eckd_generate_uid(device, &private->uid);
- dasd_get_uid(device->cdev, &temp_uid);
+ dasd_eckd_get_uid(device, &temp_uid);
+ /* Generate device unique id */
+ rc = dasd_eckd_generate_uid(device);
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
dev_err(&device->cdev->dev, "The UID of the DASD has "
"changed\n");
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
if (rc)
goto out_err;
- dasd_set_uid(device->cdev, &private->uid);
/* register lcu with alias handling, enable PAV if this is a new lcu */
is_known = dasd_alias_make_device_known_to_lcu(device);
@@ -3336,6 +3374,56 @@ out_err:
return -1;
}
+static int dasd_eckd_reload_device(struct dasd_device *device)
+{
+ struct dasd_eckd_private *private;
+ int rc, old_base;
+ char print_uid[60];
+ struct dasd_uid uid;
+ unsigned long flags;
+
+ private = (struct dasd_eckd_private *) device->private;
+
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ old_base = private->uid.base_unit_addr;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+
+ /* Read Configuration Data */
+ rc = dasd_eckd_read_conf(device);
+ if (rc)
+ goto out_err;
+
+ rc = dasd_eckd_generate_uid(device);
+ if (rc)
+ goto out_err;
+ /*
+ * update unit address configuration and
+ * add device to alias management
+ */
+ dasd_alias_update_add_device(device);
+
+ dasd_eckd_get_uid(device, &uid);
+
+ if (old_base != uid.base_unit_addr) {
+ if (strlen(uid.vduit) > 0)
+ snprintf(print_uid, sizeof(print_uid),
+ "%s.%s.%04x.%02x.%s", uid.vendor, uid.serial,
+ uid.ssid, uid.base_unit_addr, uid.vduit);
+ else
+ snprintf(print_uid, sizeof(print_uid),
+ "%s.%s.%04x.%02x", uid.vendor, uid.serial,
+ uid.ssid, uid.base_unit_addr);
+
+ dev_info(&device->cdev->dev,
+ "An Alias device was reassigned to a new base device "
+ "with UID: %s\n", print_uid);
+ }
+ return 0;
+
+out_err:
+ return -1;
+}
+
static struct ccw_driver dasd_eckd_driver = {
.name = "dasd-eckd",
.owner = THIS_MODULE,
@@ -3389,6 +3477,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
.ioctl = dasd_eckd_ioctl,
.freeze = dasd_eckd_pm_freeze,
.restore = dasd_eckd_restore_device,
+ .reload = dasd_eckd_reload_device,
+ .get_uid = dasd_eckd_get_uid,
};
static int __init
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 864d53c04201..dd6385a5af14 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -426,7 +426,6 @@ struct alias_pav_group {
struct dasd_device *next;
};
-
struct dasd_eckd_private {
struct dasd_eckd_characteristics rdc_data;
u8 *conf_data;
@@ -463,4 +462,5 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *);
void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *);
void dasd_alias_lcu_setup_complete(struct dasd_device *);
void dasd_alias_wait_for_lcu_setup(struct dasd_device *);
+int dasd_alias_update_add_device(struct dasd_device *);
#endif /* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a91d4a97d4f2..32fac186ba3f 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -81,6 +81,10 @@ struct dasd_block;
#define DASD_SIM_MSG_TO_OP 0x03
#define DASD_SIM_LOG 0x0C
+/* lock class for nested cdev lock */
+#define CDEV_NESTED_FIRST 1
+#define CDEV_NESTED_SECOND 2
+
/*
* SECTION: MACROs for klogd and s390 debug feature (dbf)
*/
@@ -229,6 +233,24 @@ struct dasd_ccw_req {
typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *);
/*
+ * Unique identifier for dasd device.
+ */
+#define UA_NOT_CONFIGURED 0x00
+#define UA_BASE_DEVICE 0x01
+#define UA_BASE_PAV_ALIAS 0x02
+#define UA_HYPER_PAV_ALIAS 0x03
+
+struct dasd_uid {
+ __u8 type;
+ char vendor[4];
+ char serial[15];
+ __u16 ssid;
+ __u8 real_unit_addr;
+ __u8 base_unit_addr;
+ char vduit[33];
+};
+
+/*
* the struct dasd_discipline is
* sth like a table of virtual functions, if you think of dasd_eckd
* inheriting dasd...
@@ -312,28 +334,15 @@ struct dasd_discipline {
/* suspend/resume functions */
int (*freeze) (struct dasd_device *);
int (*restore) (struct dasd_device *);
-};
-extern struct dasd_discipline *dasd_diag_discipline_pointer;
-
-/*
- * Unique identifier for dasd device.
- */
-#define UA_NOT_CONFIGURED 0x00
-#define UA_BASE_DEVICE 0x01
-#define UA_BASE_PAV_ALIAS 0x02
-#define UA_HYPER_PAV_ALIAS 0x03
+ /* reload device after state change */
+ int (*reload) (struct dasd_device *);
-struct dasd_uid {
- __u8 type;
- char vendor[4];
- char serial[15];
- __u16 ssid;
- __u8 real_unit_addr;
- __u8 base_unit_addr;
- char vduit[33];
+ int (*get_uid) (struct dasd_device *, struct dasd_uid *);
};
+extern struct dasd_discipline *dasd_diag_discipline_pointer;
+
/*
* Notification numbers for extended error reporting notifications:
* The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
@@ -386,6 +395,7 @@ struct dasd_device {
struct tasklet_struct tasklet;
struct work_struct kick_work;
struct work_struct restore_device;
+ struct work_struct reload_device;
struct timer_list timer;
debug_info_t *debug_area;
@@ -582,6 +592,7 @@ void dasd_enable_device(struct dasd_device *);
void dasd_set_target_state(struct dasd_device *, int);
void dasd_kick_device(struct dasd_device *);
void dasd_restore_device(struct dasd_device *);
+void dasd_reload_device(struct dasd_device *);
void dasd_add_request_head(struct dasd_ccw_req *);
void dasd_add_request_tail(struct dasd_ccw_req *);
@@ -629,8 +640,6 @@ void dasd_devmap_exit(void);
struct dasd_device *dasd_create_device(struct ccw_device *);
void dasd_delete_device(struct dasd_device *);
-int dasd_get_uid(struct ccw_device *, struct dasd_uid *);
-int dasd_set_uid(struct ccw_device *, struct dasd_uid *);
int dasd_get_feature(struct ccw_device *, int);
int dasd_set_feature(struct ccw_device *, int, int);
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 4e34d3686c23..40834f18754c 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -148,13 +148,12 @@ config VMLOGRDR
This driver depends on the IUCV support driver.
config VMCP
- tristate "Support for the z/VM CP interface (VM only)"
+ bool "Support for the z/VM CP interface"
depends on S390
help
Select this option if you want to be able to interact with the control
program on z/VM
-
config MONREADER
tristate "API for reading z/VM monitor service records"
depends on IUCV
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 0eabcca3c92d..857dfcb7b359 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -484,6 +484,7 @@ fs3270_open(struct inode *inode, struct file *filp)
raw3270_del_view(&fp->view);
goto out;
}
+ nonseekable_open(inode, filp);
filp->private_data = fp;
out:
mutex_unlock(&fs3270_mutex);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index cb6bffe7141a..18d9a497863b 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -49,7 +49,7 @@ static unsigned char ret_diacr[NR_DEAD] = {
struct kbd_data *
kbd_alloc(void) {
struct kbd_data *kbd;
- int i, len;
+ int i;
kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL);
if (!kbd)
@@ -59,12 +59,11 @@ kbd_alloc(void) {
goto out_kbd;
for (i = 0; i < ARRAY_SIZE(key_maps); i++) {
if (key_maps[i]) {
- kbd->key_maps[i] =
- kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL);
+ kbd->key_maps[i] = kmemdup(key_maps[i],
+ sizeof(u_short) * NR_KEYS,
+ GFP_KERNEL);
if (!kbd->key_maps[i])
goto out_maps;
- memcpy(kbd->key_maps[i], key_maps[i],
- sizeof(u_short)*NR_KEYS);
}
}
kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL);
@@ -72,23 +71,21 @@ kbd_alloc(void) {
goto out_maps;
for (i = 0; i < ARRAY_SIZE(func_table); i++) {
if (func_table[i]) {
- len = strlen(func_table[i]) + 1;
- kbd->func_table[i] = kmalloc(len, GFP_KERNEL);
+ kbd->func_table[i] = kstrdup(func_table[i],
+ GFP_KERNEL);
if (!kbd->func_table[i])
goto out_func;
- memcpy(kbd->func_table[i], func_table[i], len);
}
}
kbd->fn_handler =
kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL);
if (!kbd->fn_handler)
goto out_func;
- kbd->accent_table =
- kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL);
+ kbd->accent_table = kmemdup(accent_table,
+ sizeof(struct kbdiacruc) * MAX_DIACR,
+ GFP_KERNEL);
if (!kbd->accent_table)
goto out_fn_handler;
- memcpy(kbd->accent_table, accent_table,
- sizeof(struct kbdiacruc)*MAX_DIACR);
kbd->accent_table_size = accent_table_size;
return kbd;
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 5bb59d36a6d4..04e532eec032 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -1,24 +1,20 @@
/*
- * Copyright IBM Corp. 2004,2007
+ * Copyright IBM Corp. 2004,2010
* Interface implementation for communication with the z/VM control program
- * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*
* z/VMs CP offers the possibility to issue commands via the diagnose code 8
* this driver implements a character device that issues these commands and
* returns the answer of CP.
-
+ *
* The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS
*/
-#define KMSG_COMPONENT "vmcp"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
-#include <linux/module.h>
#include <linux/slab.h>
#include <asm/compat.h>
#include <asm/cpcmd.h>
@@ -26,10 +22,6 @@
#include <asm/uaccess.h>
#include "vmcp.h"
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>");
-MODULE_DESCRIPTION("z/VM CP interface");
-
static debug_info_t *vmcp_debug;
static int vmcp_open(struct inode *inode, struct file *file)
@@ -197,11 +189,8 @@ static int __init vmcp_init(void)
{
int ret;
- if (!MACHINE_IS_VM) {
- pr_warning("The z/VM CP interface device driver cannot be "
- "loaded without z/VM\n");
- return -ENODEV;
- }
+ if (!MACHINE_IS_VM)
+ return 0;
vmcp_debug = debug_register("vmcp", 1, 1, 240);
if (!vmcp_debug)
@@ -214,19 +203,8 @@ static int __init vmcp_init(void)
}
ret = misc_register(&vmcp_dev);
- if (ret) {
+ if (ret)
debug_unregister(vmcp_debug);
- return ret;
- }
-
- return 0;
-}
-
-static void __exit vmcp_exit(void)
-{
- misc_deregister(&vmcp_dev);
- debug_unregister(vmcp_debug);
+ return ret;
}
-
-module_init(vmcp_init);
-module_exit(vmcp_exit);
+device_initcall(vmcp_init);
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 7217966f7d31..f5ea3384a4b9 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -445,7 +445,7 @@ static int zcore_memmap_open(struct inode *inode, struct file *filp)
}
kfree(chunk_array);
filp->private_data = buf;
- return 0;
+ return nonseekable_open(inode, filp);
}
static int zcore_memmap_release(struct inode *inode, struct file *filp)
@@ -473,7 +473,7 @@ static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf,
static int zcore_reipl_open(struct inode *inode, struct file *filp)
{
- return 0;
+ return nonseekable_open(inode, filp);
}
static int zcore_reipl_release(struct inode *inode, struct file *filp)
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 3b6f4adc5094..a83877c664a6 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -803,6 +803,7 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd,
static const struct file_operations chsc_fops = {
.owner = THIS_MODULE,
+ .open = nonseekable_open,
.unlocked_ioctl = chsc_ioctl,
.compat_ioctl = chsc_ioctl,
};
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5feea1a371e1..f4e6cf3aceb8 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -616,7 +616,8 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
struct pt_regs *old_regs;
old_regs = set_irq_regs(regs);
- s390_idle_check();
+ s390_idle_check(regs, S390_lowcore.int_clock,
+ S390_lowcore.async_enter_timer);
irq_enter();
__get_cpu_var(s390_idle).nohz_delay = 1;
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 511649115bd7..ac94ac751459 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -648,6 +648,8 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
static void __init
css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
{
+ struct cpuid cpu_id;
+
if (css_general_characteristics.mcss) {
css->global_pgid.pgid_high.ext_cssid.version = 0x80;
css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
@@ -658,8 +660,9 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
css->global_pgid.pgid_high.cpu_addr = 0;
#endif
}
- css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident;
- css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine;
+ get_cpu_id(&cpu_id);
+ css->global_pgid.cpu_id = cpu_id.ident;
+ css->global_pgid.cpu_model = cpu_id.machine;
css->global_pgid.tod_high = tod_high;
}
@@ -1062,6 +1065,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf,
}
static const struct file_operations cio_settle_proc_fops = {
+ .open = nonseekable_open,
.write = cio_settle_write,
};
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 48aa0647432b..f0037eefd44e 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -13,8 +13,8 @@
#include <asm/debug.h>
#include "chsc.h"
-#define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */
-#define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */
+#define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */
+#define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */
/*
* if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait
@@ -296,10 +296,8 @@ struct qdio_q {
struct qdio_irq *irq_ptr;
struct sl *sl;
/*
- * Warning: Leave this member at the end so it won't be cleared in
- * qdio_fill_qs. A page is allocated under this pointer and used for
- * slib and sl. slib is 2048 bytes big and sl points to offset
- * PAGE_SIZE / 2.
+ * A page is allocated under this pointer and used for slib and sl.
+ * slib is 2048 bytes big and sl points to offset PAGE_SIZE / 2.
*/
struct slib *slib;
} __attribute__ ((aligned(256)));
@@ -372,11 +370,6 @@ static inline int multicast_outbound(struct qdio_q *q)
(q->nr == q->irq_ptr->nr_output_qs - 1);
}
-static inline unsigned long long get_usecs(void)
-{
- return monotonic_clock() >> 12;
-}
-
#define pci_out_supported(q) \
(q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)
#define is_qebsm(q) (q->irq_ptr->sch_token != 0)
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 88be7b9ea6e1..00520f9a7a8e 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -336,10 +336,10 @@ again:
WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2);
if (!start_time) {
- start_time = get_usecs();
+ start_time = get_clock();
goto again;
}
- if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE)
+ if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE)
goto again;
}
return cc;
@@ -536,7 +536,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q)
if ((bufnr != q->last_move) || q->qdio_error) {
q->last_move = bufnr;
if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR)
- q->u.in.timestamp = get_usecs();
+ q->u.in.timestamp = get_clock();
return 1;
} else
return 0;
@@ -567,7 +567,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
* At this point we know, that inbound first_to_check
* has (probably) not moved (see qdio_inbound_processing).
*/
- if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
+ if (get_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) {
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x",
q->first_to_check);
return 1;
@@ -606,7 +606,7 @@ static void qdio_kick_handler(struct qdio_q *q)
static void __qdio_inbound_processing(struct qdio_q *q)
{
qperf_inc(q, tasklet_inbound);
-again:
+
if (!qdio_inbound_q_moved(q))
return;
@@ -615,7 +615,10 @@ again:
if (!qdio_inbound_q_done(q)) {
/* means poll time is not yet over */
qperf_inc(q, tasklet_inbound_resched);
- goto again;
+ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) {
+ tasklet_schedule(&q->tasklet);
+ return;
+ }
}
qdio_stop_polling(q);
@@ -625,7 +628,8 @@ again:
*/
if (!qdio_inbound_q_done(q)) {
qperf_inc(q, tasklet_inbound_resched2);
- goto again;
+ if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED))
+ tasklet_schedule(&q->tasklet);
}
}
@@ -955,6 +959,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
return;
}
+ if (irq_ptr->perf_stat_enabled)
+ irq_ptr->perf_stat.qdio_int++;
+
if (IS_ERR(irb)) {
switch (PTR_ERR(irb)) {
case -EIO:
@@ -1016,30 +1023,6 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev,
}
EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc);
-/**
- * qdio_cleanup - shutdown queues and free data structures
- * @cdev: associated ccw device
- * @how: use halt or clear to shutdown
- *
- * This function calls qdio_shutdown() for @cdev with method @how.
- * and qdio_free(). The qdio_free() return value is ignored since
- * !irq_ptr is already checked.
- */
-int qdio_cleanup(struct ccw_device *cdev, int how)
-{
- struct qdio_irq *irq_ptr = cdev->private->qdio_data;
- int rc;
-
- if (!irq_ptr)
- return -ENODEV;
-
- rc = qdio_shutdown(cdev, how);
-
- qdio_free(cdev);
- return rc;
-}
-EXPORT_SYMBOL_GPL(qdio_cleanup);
-
static void qdio_shutdown_queues(struct ccw_device *cdev)
{
struct qdio_irq *irq_ptr = cdev->private->qdio_data;
@@ -1157,28 +1140,6 @@ int qdio_free(struct ccw_device *cdev)
EXPORT_SYMBOL_GPL(qdio_free);
/**
- * qdio_initialize - allocate and establish queues for a qdio subchannel
- * @init_data: initialization data
- *
- * This function first allocates queues via qdio_allocate() and on success
- * establishes them via qdio_establish().
- */
-int qdio_initialize(struct qdio_initialize *init_data)
-{
- int rc;
-
- rc = qdio_allocate(init_data);
- if (rc)
- return rc;
-
- rc = qdio_establish(init_data);
- if (rc)
- qdio_free(init_data->cdev);
- return rc;
-}
-EXPORT_SYMBOL_GPL(qdio_initialize);
-
-/**
* qdio_allocate - allocate qdio queues and associated data
* @init_data: initialization data
*/
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c
index 7f4a75465140..6326b67c45d2 100644
--- a/drivers/s390/cio/qdio_setup.c
+++ b/drivers/s390/cio/qdio_setup.c
@@ -106,10 +106,12 @@ int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs
static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr,
qdio_handler_t *handler, int i)
{
- /* must be cleared by every qdio_establish */
- memset(q, 0, ((char *)&q->slib) - ((char *)q));
- memset(q->slib, 0, PAGE_SIZE);
+ struct slib *slib = q->slib;
+ /* queue must be cleared for qdio_establish */
+ memset(q, 0, sizeof(*q));
+ memset(slib, 0, PAGE_SIZE);
+ q->slib = slib;
q->irq_ptr = irq_ptr;
q->mask = 1 << (31 - i);
q->nr = i;
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index ce5f8910ff83..8daf1b99f153 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -95,7 +95,7 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr)
for_each_input_queue(irq_ptr, q, i)
list_add_rcu(&q->entry, &tiq_list);
mutex_unlock(&tiq_list_lock);
- xchg(irq_ptr->dsci, 1);
+ xchg(irq_ptr->dsci, 1 << 7);
}
void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr)
@@ -173,7 +173,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data)
/* prevent racing */
if (*tiqdio_alsi)
- xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1);
+ xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7);
}
}
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index 304caf549973..41e0aaefafd5 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -302,7 +302,7 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
static int zcrypt_open(struct inode *inode, struct file *filp)
{
atomic_inc(&zcrypt_open_count);
- return 0;
+ return nonseekable_open(inode, filp);
}
/**
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3ba738b2e271..28f71349fdec 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1292,13 +1292,14 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
QETH_QDIO_CLEANING)) {
case QETH_QDIO_ESTABLISHED:
if (card->info.type == QETH_CARD_TYPE_IQD)
- rc = qdio_cleanup(CARD_DDEV(card),
+ rc = qdio_shutdown(CARD_DDEV(card),
QDIO_FLAG_CLEANUP_USING_HALT);
else
- rc = qdio_cleanup(CARD_DDEV(card),
+ rc = qdio_shutdown(CARD_DDEV(card),
QDIO_FLAG_CLEANUP_USING_CLEAR);
if (rc)
QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc);
+ qdio_free(CARD_DDEV(card));
atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
break;
case QETH_QDIO_CLEANING:
@@ -3810,10 +3811,18 @@ static int qeth_qdio_establish(struct qeth_card *card)
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) {
- rc = qdio_initialize(&init_data);
- if (rc)
+ rc = qdio_allocate(&init_data);
+ if (rc) {
+ atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
+ goto out;
+ }
+ rc = qdio_establish(&init_data);
+ if (rc) {
atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
+ qdio_free(CARD_DDEV(card));
+ }
}
+out:
kfree(out_sbal_ptrs);
kfree(in_sbal_ptrs);
kfree(qib_param_field);
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index 25d9e0ae9c57..1a2db0a35737 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -254,6 +254,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
}
static const struct file_operations zfcp_cfdc_fops = {
+ .open = nonseekable_open,
.unlocked_ioctl = zfcp_cfdc_dev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = zfcp_cfdc_dev_ioctl
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 9201afe65609..7f87979da22d 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -4724,6 +4724,10 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(board->dev, asc_dvc->overrun_dma)) {
+ warn_code = -ENOMEM;
+ goto err_dma_map;
+ }
phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
(uchar *)&phy_addr, 1);
@@ -4739,14 +4743,23 @@ static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return warn_code;
+ warn_code = UW_ERR;
+ goto err_mcode_start;
}
if (AscStartChip(iop_base) != 1) {
asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return warn_code;
+ warn_code = UW_ERR;
+ goto err_mcode_start;
}
return warn_code;
+
+err_mcode_start:
+ dma_unmap_single(board->dev, asc_dvc->overrun_dma,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+err_dma_map:
+ asc_dvc->overrun_dma = 0;
+ return warn_code;
}
static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
@@ -4802,6 +4815,8 @@ static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
}
release_firmware(fw);
warn_code |= AscInitMicroCodeVar(asc_dvc);
+ if (!asc_dvc->overrun_dma)
+ return warn_code;
asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
AscEnableInterrupt(iop_base);
return warn_code;
@@ -7978,9 +7993,10 @@ static int advansys_reset(struct scsi_cmnd *scp)
status = AscInitAsc1000Driver(asc_dvc);
/* Refer to ASC_IERR_* definitions for meaning of 'err_code'. */
- if (asc_dvc->err_code) {
+ if (asc_dvc->err_code || !asc_dvc->overrun_dma) {
scmd_printk(KERN_INFO, scp, "SCSI bus reset error: "
- "0x%x\n", asc_dvc->err_code);
+ "0x%x, status: 0x%x\n", asc_dvc->err_code,
+ status);
ret = FAILED;
} else if (status) {
scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
@@ -12311,7 +12327,7 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL);
if (!asc_dvc_varp->overrun_buf) {
ret = -ENOMEM;
- goto err_free_wide_mem;
+ goto err_free_irq;
}
warn_code = AscInitAsc1000Driver(asc_dvc_varp);
@@ -12320,30 +12336,36 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost,
"warn 0x%x, error 0x%x\n",
asc_dvc_varp->init_state, warn_code,
asc_dvc_varp->err_code);
- if (asc_dvc_varp->err_code) {
+ if (!asc_dvc_varp->overrun_dma) {
ret = -ENODEV;
- kfree(asc_dvc_varp->overrun_buf);
+ goto err_free_mem;
}
}
} else {
- if (advansys_wide_init_chip(shost))
+ if (advansys_wide_init_chip(shost)) {
ret = -ENODEV;
+ goto err_free_mem;
+ }
}
- if (ret)
- goto err_free_wide_mem;
-
ASC_DBG_PRT_SCSI_HOST(2, shost);
ret = scsi_add_host(shost, boardp->dev);
if (ret)
- goto err_free_wide_mem;
+ goto err_free_mem;
scsi_scan_host(shost);
return 0;
- err_free_wide_mem:
- advansys_wide_free_mem(boardp);
+ err_free_mem:
+ if (ASC_NARROW_BOARD(boardp)) {
+ if (asc_dvc_varp->overrun_dma)
+ dma_unmap_single(boardp->dev, asc_dvc_varp->overrun_dma,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ kfree(asc_dvc_varp->overrun_buf);
+ } else
+ advansys_wide_free_mem(boardp);
+ err_free_irq:
free_irq(boardp->irq, shost);
err_free_dma:
#ifdef CONFIG_ISA
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 6d5ae4474bb3..633e09036357 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -471,12 +471,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task)
WARN_ON(hdrlength >= 256);
hdr->hlength = hdrlength & 0xFF;
+ hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
if (session->tt->init_task && session->tt->init_task(task))
return -EIO;
task->state = ISCSI_TASK_RUNNING;
- hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
conn->scsicmd_pdus_cnt++;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index b00efd19aadb..88f744672576 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -395,11 +395,15 @@ int sas_ata_init_host_and_port(struct domain_device *found_dev,
void sas_ata_task_abort(struct sas_task *task)
{
struct ata_queued_cmd *qc = task->uldd_task;
+ struct request_queue *q = qc->scsicmd->device->request_queue;
struct completion *waiting;
+ unsigned long flags;
/* Bounce SCSI-initiated commands to the SCSI EH */
if (qc->scsicmd) {
+ spin_lock_irqsave(q->queue_lock, flags);
blk_abort_request(qc->scsicmd->request);
+ spin_unlock_irqrestore(q->queue_lock, flags);
scsi_schedule_eh(qc->scsicmd->device->host);
return;
}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 2660e1b4569a..822835055cef 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -1030,6 +1030,8 @@ int __sas_task_abort(struct sas_task *task)
void sas_task_abort(struct sas_task *task)
{
struct scsi_cmnd *sc = task->uldd_task;
+ struct request_queue *q = sc->device->request_queue;
+ unsigned long flags;
/* Escape for libsas internal commands */
if (!sc) {
@@ -1044,7 +1046,9 @@ void sas_task_abort(struct sas_task *task)
return;
}
+ spin_lock_irqsave(q->queue_lock, flags);
blk_abort_request(sc->request);
+ spin_unlock_irqrestore(q->queue_lock, flags);
scsi_schedule_eh(sc->device->host);
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 3e10c306de94..3a5bfd10b2cb 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -957,7 +957,8 @@ static int resp_start_stop(struct scsi_cmnd * scp,
static sector_t get_sdebug_capacity(void)
{
if (scsi_debug_virtual_gb > 0)
- return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
+ return (sector_t)scsi_debug_virtual_gb *
+ (1073741824 / scsi_debug_sector_size);
else
return sdebug_store_sectors;
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index d45c69ca5737..7ad53fa42766 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -302,7 +302,20 @@ static int scsi_check_sense(struct scsi_cmnd *scmd)
if (scmd->device->allow_restart &&
(sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
return FAILED;
- return SUCCESS;
+
+ if (blk_barrier_rq(scmd->request))
+ /*
+ * barrier requests should always retry on UA
+ * otherwise block will get a spurious error
+ */
+ return NEEDS_RETRY;
+ else
+ /*
+ * for normal (non barrier) commands, pass the
+ * UA upwards for a determination in the
+ * completion functions
+ */
+ return SUCCESS;
/* these three are not supported */
case COPY_ABORTED:
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8b827f37b03e..de6c60320f6f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1040,6 +1040,7 @@ static void sd_prepare_flush(struct request_queue *q, struct request *rq)
{
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = SD_TIMEOUT;
+ rq->retries = SD_MAX_RETRIES;
rq->cmd[0] = SYNCHRONIZE_CACHE;
rq->cmd_len = 10;
}
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index 105449c15fa9..e17764d71476 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -69,6 +69,7 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
},
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, zorro7xx_zorro_tbl);
static int __devinit zorro7xx_init_one(struct zorro_dev *z,
const struct zorro_device_id *ent)
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 2c9bf9b68327..eed3c2d8dd1c 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -38,6 +38,7 @@
#include <linux/dma-mapping.h>
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
@@ -59,6 +60,9 @@
#include <linux/serial_core.h>
+static void atmel_start_rx(struct uart_port *port);
+static void atmel_stop_rx(struct uart_port *port);
+
#ifdef CONFIG_SERIAL_ATMEL_TTYAT
/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
@@ -93,6 +97,7 @@
#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR)
#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
+#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR)
/* PDC registers */
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
@@ -147,6 +152,9 @@ struct atmel_uart_port {
unsigned int irq_status_prev;
struct circ_buf rx_ring;
+
+ struct serial_rs485 rs485; /* rs485 settings */
+ unsigned int tx_done_mask;
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -187,6 +195,46 @@ static bool atmel_use_dma_tx(struct uart_port *port)
}
#endif
+/* Enable or disable the rs485 support */
+void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
+{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ unsigned int mode;
+
+ spin_lock(&port->lock);
+
+ /* Disable interrupts */
+ UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+ mode = UART_GET_MR(port);
+
+ /* Resetting serial mode to RS232 (0x0) */
+ mode &= ~ATMEL_US_USMODE;
+
+ atmel_port->rs485 = *rs485conf;
+
+ if (rs485conf->flags & SER_RS485_ENABLED) {
+ dev_dbg(port->dev, "Setting UART to RS485\n");
+ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+ UART_PUT_TTGR(port, rs485conf->delay_rts_before_send);
+ mode |= ATMEL_US_USMODE_RS485;
+ } else {
+ dev_dbg(port->dev, "Setting UART to RS232\n");
+ if (atmel_use_dma_tx(port))
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+ ATMEL_US_TXBUFE;
+ else
+ atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+ }
+ UART_PUT_MR(port, mode);
+
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+
+ spin_unlock(&port->lock);
+
+}
+
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
@@ -202,6 +250,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
{
unsigned int control = 0;
unsigned int mode;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
#ifdef CONFIG_ARCH_AT91RM9200
if (cpu_is_at91rm9200()) {
@@ -236,6 +285,17 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
mode |= ATMEL_US_CHMODE_LOC_LOOP;
else
mode |= ATMEL_US_CHMODE_NORMAL;
+
+ /* Resetting serial mode to RS232 (0x0) */
+ mode &= ~ATMEL_US_USMODE;
+
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+ dev_dbg(port->dev, "Setting UART to RS485\n");
+ UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_before_send);
+ mode |= ATMEL_US_USMODE_RS485;
+ } else {
+ dev_dbg(port->dev, "Setting UART to RS232\n");
+ }
UART_PUT_MR(port, mode);
}
@@ -268,12 +328,17 @@ static u_int atmel_get_mctrl(struct uart_port *port)
*/
static void atmel_stop_tx(struct uart_port *port)
{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
if (atmel_use_dma_tx(port)) {
/* disable PDC transmit */
UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
- UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
- } else
- UART_PUT_IDR(port, ATMEL_US_TXRDY);
+ }
+ /* Disable interrupts */
+ UART_PUT_IDR(port, atmel_port->tx_done_mask);
+
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+ atmel_start_rx(port);
}
/*
@@ -281,17 +346,39 @@ static void atmel_stop_tx(struct uart_port *port)
*/
static void atmel_start_tx(struct uart_port *port)
{
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
if (atmel_use_dma_tx(port)) {
if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
/* The transmitter is already running. Yes, we
really need this.*/
return;
- UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+ atmel_stop_rx(port);
+
/* re-enable PDC transmit */
UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
- } else
- UART_PUT_IER(port, ATMEL_US_TXRDY);
+ }
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+}
+
+/*
+ * start receiving - port is in process of being opened.
+ */
+static void atmel_start_rx(struct uart_port *port)
+{
+ UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */
+
+ if (atmel_use_dma_rx(port)) {
+ /* enable PDC controller */
+ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+ port->read_status_mask);
+ UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+ } else {
+ UART_PUT_IER(port, ATMEL_US_RXRDY);
+ }
}
/*
@@ -302,9 +389,11 @@ static void atmel_stop_rx(struct uart_port *port)
if (atmel_use_dma_rx(port)) {
/* disable PDC receive */
UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
- UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
- } else
+ UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
+ port->read_status_mask);
+ } else {
UART_PUT_IDR(port, ATMEL_US_RXRDY);
+ }
}
/*
@@ -428,8 +517,9 @@ static void atmel_rx_chars(struct uart_port *port)
static void atmel_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) {
+ if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) {
UART_PUT_CHAR(port, port->x_char);
port->icount.tx++;
port->x_char = 0;
@@ -437,7 +527,7 @@ static void atmel_tx_chars(struct uart_port *port)
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
- while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
+ while (UART_GET_CSR(port) & atmel_port->tx_done_mask) {
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
@@ -449,7 +539,8 @@ static void atmel_tx_chars(struct uart_port *port)
uart_write_wakeup(port);
if (!uart_circ_empty(xmit))
- UART_PUT_IER(port, ATMEL_US_TXRDY);
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
}
/*
@@ -501,18 +592,10 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- if (atmel_use_dma_tx(port)) {
- /* PDC transmit */
- if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) {
- UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
- tasklet_schedule(&atmel_port->tasklet);
- }
- } else {
- /* Interrupt transmit */
- if (pending & ATMEL_US_TXRDY) {
- UART_PUT_IDR(port, ATMEL_US_TXRDY);
- tasklet_schedule(&atmel_port->tasklet);
- }
+ if (pending & atmel_port->tx_done_mask) {
+ /* Either PDC or interrupt transmission */
+ UART_PUT_IDR(port, atmel_port->tx_done_mask);
+ tasklet_schedule(&atmel_port->tasklet);
}
}
@@ -590,9 +673,15 @@ static void atmel_tx_dma(struct uart_port *port)
UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
UART_PUT_TCR(port, count);
- /* re-enable PDC transmit and interrupts */
+ /* re-enable PDC transmit */
UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);
- UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+ /* Enable interrupts */
+ UART_PUT_IER(port, atmel_port->tx_done_mask);
+ } else {
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+ /* DMA done, stop TX, start RX for RS485 */
+ atmel_start_rx(port);
+ }
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -1017,6 +1106,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
{
unsigned long flags;
unsigned int mode, imr, quot, baud;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/* Get current mode register */
mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
@@ -1115,6 +1205,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
/* disable receiver and transmitter */
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+ /* Resetting serial mode to RS232 (0x0) */
+ mode &= ~ATMEL_US_USMODE;
+
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+ dev_dbg(port->dev, "Setting UART to RS485\n");
+ UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_before_send);
+ mode |= ATMEL_US_USMODE_RS485;
+ } else {
+ dev_dbg(port->dev, "Setting UART to RS232\n");
+ }
+
/* set the parity, stop bits and data size */
UART_PUT_MR(port, mode);
@@ -1231,6 +1332,35 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch)
}
#endif
+static int
+atmel_ioctl(struct uart_port *port, unsigned int cmd, unsigned long arg)
+{
+ struct serial_rs485 rs485conf;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ if (copy_from_user(&rs485conf, (struct serial_rs485 *) arg,
+ sizeof(rs485conf)))
+ return -EFAULT;
+
+ atmel_config_rs485(port, &rs485conf);
+ break;
+
+ case TIOCGRS485:
+ if (copy_to_user((struct serial_rs485 *) arg,
+ &(to_atmel_uart_port(port)->rs485),
+ sizeof(rs485conf)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+
+
static struct uart_ops atmel_pops = {
.tx_empty = atmel_tx_empty,
.set_mctrl = atmel_set_mctrl,
@@ -1250,6 +1380,7 @@ static struct uart_ops atmel_pops = {
.config_port = atmel_config_port,
.verify_port = atmel_verify_port,
.pm = atmel_serial_pm,
+ .ioctl = atmel_ioctl,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = atmel_poll_get_char,
.poll_put_char = atmel_poll_put_char,
@@ -1265,13 +1396,12 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
struct uart_port *port = &atmel_port->uart;
struct atmel_uart_data *data = pdev->dev.platform_data;
- port->iotype = UPIO_MEM;
- port->flags = UPF_BOOT_AUTOCONF;
- port->ops = &atmel_pops;
- port->fifosize = 1;
- port->line = pdev->id;
- port->dev = &pdev->dev;
-
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &atmel_pops;
+ port->fifosize = 1;
+ port->line = pdev->id;
+ port->dev = &pdev->dev;
port->mapbase = pdev->resource[0].start;
port->irq = pdev->resource[1].start;
@@ -1299,8 +1429,16 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
atmel_port->use_dma_rx = data->use_dma_rx;
atmel_port->use_dma_tx = data->use_dma_tx;
- if (atmel_use_dma_tx(port))
+ atmel_port->rs485 = data->rs485;
+ /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
+ if (atmel_port->rs485.flags & SER_RS485_ENABLED)
+ atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
+ else if (atmel_use_dma_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE;
+ atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
+ } else {
+ atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+ }
}
/*
@@ -1334,6 +1472,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch)
static void atmel_console_write(struct console *co, const char *s, u_int count)
{
struct uart_port *port = &atmel_ports[co->index].uart;
+ struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int status, imr;
unsigned int pdc_tx;
@@ -1341,7 +1480,7 @@ static void atmel_console_write(struct console *co, const char *s, u_int count)
* First, save IMR and then disable interrupts
*/
imr = UART_GET_IMR(port);
- UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
+ UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask);
/* Store PDC transmit status and disable it */
pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN;
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 4315b23590bd..eacb588a9345 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -120,7 +120,8 @@
#define MX2_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select, on mx2/mx3 */
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
#define UCR3_BPEN (1<<0) /* Preset registers enable */
-#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
+#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */
+#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */
#define UCR4_INVR (1<<9) /* Inverted infrared reception */
#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
@@ -591,6 +592,9 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
return 0;
}
+/* half the RX buffer size */
+#define CTSTL 16
+
static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
@@ -607,6 +611,10 @@ static int imx_startup(struct uart_port *port)
if (USE_IRDA(sport))
temp |= UCR4_IRSC;
+ /* set the trigger level for CTS */
+ temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF);
+ temp |= CTSTL<< UCR4_CTSTL_SHF;
+
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
if (USE_IRDA(sport)) {
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index a176ab4bd65b..02469c31bf0b 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -1467,7 +1467,7 @@ mpc52xx_uart_init(void)
/*
* Map the PSC FIFO Controller and init if on MPC512x.
*/
- if (psc_ops->fifoc_init) {
+ if (psc_ops && psc_ops->fifoc_init) {
ret = psc_ops->fifoc_init();
if (ret)
return ret;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 8eb094c1f61b..8d993c4cceac 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -83,16 +83,16 @@ struct sci_port {
/* Interface clock */
struct clk *iclk;
- /* Data clock */
- struct clk *dclk;
+ /* Function clock */
+ struct clk *fclk;
struct list_head node;
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
struct device *dma_dev;
- enum sh_dmae_slave_chan_id slave_tx;
- enum sh_dmae_slave_chan_id slave_rx;
+ unsigned int slave_tx;
+ unsigned int slave_rx;
struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx[2];
dma_cookie_t cookie_tx;
@@ -107,6 +107,7 @@ struct sci_port {
struct work_struct work_tx;
struct work_struct work_rx;
struct timer_list rx_timer;
+ unsigned int rx_timeout;
#endif
};
@@ -674,22 +675,22 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
struct sci_port *s = to_sci_port(port);
if (s->chan_rx) {
- unsigned long tout;
u16 scr = sci_in(port, SCSCR);
u16 ssr = sci_in(port, SCxSR);
/* Disable future Rx interrupts */
- sci_out(port, SCSCR, scr & ~SCI_CTRL_FLAGS_RIE);
+ if (port->type == PORT_SCIFA) {
+ disable_irq_nosync(irq);
+ scr |= 0x4000;
+ } else {
+ scr &= ~SCI_CTRL_FLAGS_RIE;
+ }
+ sci_out(port, SCSCR, scr);
/* Clear current interrupt */
sci_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
- /* Calculate delay for 1.5 DMA buffers */
- tout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
- port->fifosize / 2;
- dev_dbg(port->dev, "Rx IRQ: setup timeout in %lu ms\n",
- tout * 1000 / HZ);
- if (tout < 2)
- tout = 2;
- mod_timer(&s->rx_timer, jiffies + tout);
+ dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+ jiffies, s->rx_timeout);
+ mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
return IRQ_HANDLED;
}
@@ -799,7 +800,7 @@ static int sci_notifier(struct notifier_block *self,
(phase == CPUFREQ_RESUMECHANGE)) {
spin_lock_irqsave(&priv->lock, flags);
list_for_each_entry(sci_port, &priv->ports, node)
- sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
+ sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -810,21 +811,17 @@ static void sci_clk_enable(struct uart_port *port)
{
struct sci_port *sci_port = to_sci_port(port);
- clk_enable(sci_port->dclk);
- sci_port->port.uartclk = clk_get_rate(sci_port->dclk);
-
- if (sci_port->iclk)
- clk_enable(sci_port->iclk);
+ clk_enable(sci_port->iclk);
+ sci_port->port.uartclk = clk_get_rate(sci_port->iclk);
+ clk_enable(sci_port->fclk);
}
static void sci_clk_disable(struct uart_port *port)
{
struct sci_port *sci_port = to_sci_port(port);
- if (sci_port->iclk)
- clk_disable(sci_port->iclk);
-
- clk_disable(sci_port->dclk);
+ clk_disable(sci_port->fclk);
+ clk_disable(sci_port->iclk);
}
static int sci_request_irq(struct sci_port *port)
@@ -913,22 +910,26 @@ static void sci_dma_tx_complete(void *arg)
spin_lock_irqsave(&port->lock, flags);
- xmit->tail += s->sg_tx.length;
+ xmit->tail += sg_dma_len(&s->sg_tx);
xmit->tail &= UART_XMIT_SIZE - 1;
- port->icount.tx += s->sg_tx.length;
+ port->icount.tx += sg_dma_len(&s->sg_tx);
async_tx_ack(s->desc_tx);
s->cookie_tx = -EINVAL;
s->desc_tx = NULL;
- spin_unlock_irqrestore(&port->lock, flags);
-
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_chars_pending(xmit))
+ if (!uart_circ_empty(xmit)) {
schedule_work(&s->work_tx);
+ } else if (port->type == PORT_SCIFA) {
+ u16 ctrl = sci_in(port, SCSCR);
+ sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
}
/* Locking: called with port lock held */
@@ -972,13 +973,13 @@ static void sci_dma_rx_complete(void *arg)
unsigned long flags;
int count;
- dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ dev_dbg(port->dev, "%s(%d) active #%d\n", __func__, port->line, s->active_rx);
spin_lock_irqsave(&port->lock, flags);
count = sci_dma_rx_push(s, tty, s->buf_len_rx);
- mod_timer(&s->rx_timer, jiffies + msecs_to_jiffies(5));
+ mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
spin_unlock_irqrestore(&port->lock, flags);
@@ -1050,6 +1051,8 @@ static void sci_submit_rx(struct sci_port *s)
sci_rx_dma_release(s, true);
return;
}
+ dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+ s->cookie_rx[i], i);
}
s->active_rx = s->cookie_rx[0];
@@ -1107,10 +1110,10 @@ static void work_fn_rx(struct work_struct *work)
return;
}
- dev_dbg(port->dev, "%s: cookie %d #%d\n", __func__,
- s->cookie_rx[new], new);
-
s->active_rx = s->cookie_rx[!new];
+
+ dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", __func__,
+ s->cookie_rx[new], new, s->active_rx);
}
static void work_fn_tx(struct work_struct *work)
@@ -1131,14 +1134,13 @@ static void work_fn_tx(struct work_struct *work)
*/
spin_lock_irq(&port->lock);
sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
- sg->dma_address = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
+ sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
sg->offset;
- sg->length = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+ sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
- sg->dma_length = sg->length;
spin_unlock_irq(&port->lock);
- BUG_ON(!sg->length);
+ BUG_ON(!sg_dma_len(sg));
desc = chan->device->device_prep_slave_sg(chan,
sg, s->sg_len_tx, DMA_TO_DEVICE,
@@ -1173,23 +1175,28 @@ static void work_fn_tx(struct work_struct *work)
static void sci_start_tx(struct uart_port *port)
{
+ struct sci_port *s = to_sci_port(port);
unsigned short ctrl;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
- struct sci_port *s = to_sci_port(port);
-
- if (s->chan_tx) {
- if (!uart_circ_empty(&s->port.state->xmit) && s->cookie_tx < 0)
- schedule_work(&s->work_tx);
-
- return;
+ if (port->type == PORT_SCIFA) {
+ u16 new, scr = sci_in(port, SCSCR);
+ if (s->chan_tx)
+ new = scr | 0x8000;
+ else
+ new = scr & ~0x8000;
+ if (new != scr)
+ sci_out(port, SCSCR, new);
}
+ if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+ s->cookie_tx < 0)
+ schedule_work(&s->work_tx);
#endif
-
- /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
- ctrl = sci_in(port, SCSCR);
- ctrl |= SCI_CTRL_FLAGS_TIE;
- sci_out(port, SCSCR, ctrl);
+ if (!s->chan_tx || port->type == PORT_SCIFA) {
+ /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+ ctrl = sci_in(port, SCSCR);
+ sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
+ }
}
static void sci_stop_tx(struct uart_port *port)
@@ -1198,6 +1205,8 @@ static void sci_stop_tx(struct uart_port *port)
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
+ if (port->type == PORT_SCIFA)
+ ctrl &= ~0x8000;
ctrl &= ~SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
}
@@ -1208,6 +1217,8 @@ static void sci_start_rx(struct uart_port *port)
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl |= sci_in(port, SCSCR);
+ if (port->type == PORT_SCIFA)
+ ctrl &= ~0x4000;
sci_out(port, SCSCR, ctrl);
}
@@ -1217,6 +1228,8 @@ static void sci_stop_rx(struct uart_port *port)
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
+ if (port->type == PORT_SCIFA)
+ ctrl &= ~0x4000;
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
sci_out(port, SCSCR, ctrl);
}
@@ -1251,8 +1264,12 @@ static void rx_timer_fn(unsigned long arg)
{
struct sci_port *s = (struct sci_port *)arg;
struct uart_port *port = &s->port;
-
u16 scr = sci_in(port, SCSCR);
+
+ if (port->type == PORT_SCIFA) {
+ scr &= ~0x4000;
+ enable_irq(s->irqs[1]);
+ }
sci_out(port, SCSCR, scr | SCI_CTRL_FLAGS_RIE);
dev_dbg(port->dev, "DMA Rx timed out\n");
schedule_work(&s->work_rx);
@@ -1339,8 +1356,7 @@ static void sci_request_dma(struct uart_port *port)
sg_init_table(sg, 1);
sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
(int)buf[i] & ~PAGE_MASK);
- sg->dma_address = dma[i];
- sg->dma_length = sg->length;
+ sg_dma_address(sg) = dma[i];
}
INIT_WORK(&s->work_rx, work_fn_rx);
@@ -1403,8 +1419,12 @@ static void sci_shutdown(struct uart_port *port)
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct sci_port *s = to_sci_port(port);
+#endif
unsigned int status, baud, smr_val, max_baud;
int t = -1;
+ u16 scfcr = 0;
/*
* earlyprintk comes here early on with port->uartclk set to zero.
@@ -1427,7 +1447,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
if (port->type != PORT_SCI)
- sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+ sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
smr_val = sci_in(port, SCSMR) & 3;
if ((termios->c_cflag & CSIZE) == CS7)
@@ -1458,10 +1478,32 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
}
sci_init_pins(port, termios->c_cflag);
- sci_out(port, SCFCR, (termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0);
+ sci_out(port, SCFCR, scfcr | ((termios->c_cflag & CRTSCTS) ? SCFCR_MCE : 0));
sci_out(port, SCSCR, SCSCR_INIT(port));
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ /*
+ * Calculate delay for 1.5 DMA buffers: see
+ * drivers/serial/serial_core.c::uart_update_timeout(). With 10 bits
+ * (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
+ * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
+ * Then below we calculate 3 jiffies (12ms) for 1.5 DMA buffers (3 FIFO
+ * sizes), but it has been found out experimentally, that this is not
+ * enough: the driver too often needlessly runs on a DMA timeout. 20ms
+ * as a minimum seem to work perfectly.
+ */
+ if (s->chan_rx) {
+ s->rx_timeout = (port->timeout - HZ / 50) * s->buf_len_rx * 3 /
+ port->fifosize / 2;
+ dev_dbg(port->dev,
+ "DMA Rx t-out %ums, tty t-out %u jiffies\n",
+ s->rx_timeout * 1000 / HZ, port->timeout);
+ if (s->rx_timeout < msecs_to_jiffies(20))
+ s->rx_timeout = msecs_to_jiffies(20);
+ }
+#endif
+
if ((termios->c_cflag & CREAD) != 0)
sci_start_rx(port);
}
@@ -1553,10 +1595,10 @@ static struct uart_ops sci_uart_ops = {
#endif
};
-static void __devinit sci_init_single(struct platform_device *dev,
- struct sci_port *sci_port,
- unsigned int index,
- struct plat_sci_port *p)
+static int __devinit sci_init_single(struct platform_device *dev,
+ struct sci_port *sci_port,
+ unsigned int index,
+ struct plat_sci_port *p)
{
struct uart_port *port = &sci_port->port;
@@ -1577,8 +1619,23 @@ static void __devinit sci_init_single(struct platform_device *dev,
}
if (dev) {
- sci_port->iclk = p->clk ? clk_get(&dev->dev, p->clk) : NULL;
- sci_port->dclk = clk_get(&dev->dev, "peripheral_clk");
+ sci_port->iclk = clk_get(&dev->dev, "sci_ick");
+ if (IS_ERR(sci_port->iclk)) {
+ sci_port->iclk = clk_get(&dev->dev, "peripheral_clk");
+ if (IS_ERR(sci_port->iclk)) {
+ dev_err(&dev->dev, "can't get iclk\n");
+ return PTR_ERR(sci_port->iclk);
+ }
+ }
+
+ /*
+ * The function clock is optional, ignore it if we can't
+ * find it.
+ */
+ sci_port->fclk = clk_get(&dev->dev, "sci_fck");
+ if (IS_ERR(sci_port->fclk))
+ sci_port->fclk = NULL;
+
sci_port->enable = sci_clk_enable;
sci_port->disable = sci_clk_disable;
port->dev = &dev->dev;
@@ -1605,6 +1662,7 @@ static void __devinit sci_init_single(struct platform_device *dev,
#endif
memcpy(&sci_port->irqs, &p->irqs, sizeof(p->irqs));
+ return 0;
}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
@@ -1754,8 +1812,11 @@ static int sci_remove(struct platform_device *dev)
cpufreq_unregister_notifier(&priv->clk_nb, CPUFREQ_TRANSITION_NOTIFIER);
spin_lock_irqsave(&priv->lock, flags);
- list_for_each_entry(p, &priv->ports, node)
+ list_for_each_entry(p, &priv->ports, node) {
uart_remove_one_port(&sci_uart_driver, &p->port);
+ clk_put(p->iclk);
+ clk_put(p->fclk);
+ }
spin_unlock_irqrestore(&priv->lock, flags);
kfree(priv);
@@ -1781,7 +1842,9 @@ static int __devinit sci_probe_single(struct platform_device *dev,
return 0;
}
- sci_init_single(dev, sciport, index, p);
+ ret = sci_init_single(dev, sciport, index, p);
+ if (ret)
+ return ret;
ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
if (ret)
diff --git a/drivers/sh/Kconfig b/drivers/sh/Kconfig
new file mode 100644
index 000000000000..a54de0b9b3df
--- /dev/null
+++ b/drivers/sh/Kconfig
@@ -0,0 +1,24 @@
+config INTC_USERIMASK
+ bool "Userspace interrupt masking support"
+ depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A)
+ help
+ This enables support for hardware-assisted userspace hardirq
+ masking.
+
+ SH-4A and newer interrupt blocks all support a special shadowed
+ page with all non-masking registers obscured when mapped in to
+ userspace. This is primarily for use by userspace device
+ drivers that are using special priority levels.
+
+ If in doubt, say N.
+
+config INTC_BALANCING
+ bool "Hardware IRQ balancing support"
+ depends on SMP && SUPERH && CPU_SUBTYPE_SH7786
+ help
+ This enables support for IRQ auto-distribution mode on SH-X3
+ SMP parts. All of the balancing and CPU wakeup decisions are
+ taken care of automatically by hardware for distributed
+ vectors.
+
+ If in doubt, say N.
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 4956bf1f2134..78bb5127abd0 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -4,4 +4,6 @@
obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_MAPLE) += maple/
obj-$(CONFIG_GENERIC_GPIO) += pfc.o
+obj-$(CONFIG_SUPERH) += clk.o
+obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o
obj-y += intc.o
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk-cpg.c
new file mode 100644
index 000000000000..f5c80ba9ab1c
--- /dev/null
+++ b/drivers/sh/clk-cpg.c
@@ -0,0 +1,298 @@
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+
+static int sh_clk_mstp32_enable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
+ clk->enable_reg);
+ return 0;
+}
+
+static void sh_clk_mstp32_disable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
+ clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_mstp32_clk_ops = {
+ .enable = sh_clk_mstp32_enable,
+ .disable = sh_clk_mstp32_disable,
+ .recalc = followparent_recalc,
+};
+
+int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+ struct clk *clkp;
+ int ret = 0;
+ int k;
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+ clkp->ops = &sh_clk_mstp32_clk_ops;
+ ret |= clk_register(clkp);
+ }
+
+ return ret;
+}
+
+static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_rate_table_round(clk, clk->freq_table, rate);
+}
+
+static int sh_clk_div6_divisors[64] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
+};
+
+static struct clk_div_mult_table sh_clk_div6_table = {
+ .divisors = sh_clk_div6_divisors,
+ .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
+};
+
+static unsigned long sh_clk_div6_recalc(struct clk *clk)
+{
+ struct clk_div_mult_table *table = &sh_clk_div6_table;
+ unsigned int idx;
+
+ clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+ table, NULL);
+
+ idx = __raw_readl(clk->enable_reg) & 0x003f;
+
+ return clk->freq_table[idx].frequency;
+}
+
+static int sh_clk_div6_set_rate(struct clk *clk,
+ unsigned long rate, int algo_id)
+{
+ unsigned long value;
+ int idx;
+
+ idx = clk_rate_table_find(clk, clk->freq_table, rate);
+ if (idx < 0)
+ return idx;
+
+ value = __raw_readl(clk->enable_reg);
+ value &= ~0x3f;
+ value |= idx;
+ __raw_writel(value, clk->enable_reg);
+ return 0;
+}
+
+static int sh_clk_div6_enable(struct clk *clk)
+{
+ unsigned long value;
+ int ret;
+
+ ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
+ if (ret == 0) {
+ value = __raw_readl(clk->enable_reg);
+ value &= ~0x100; /* clear stop bit to enable clock */
+ __raw_writel(value, clk->enable_reg);
+ }
+ return ret;
+}
+
+static void sh_clk_div6_disable(struct clk *clk)
+{
+ unsigned long value;
+
+ value = __raw_readl(clk->enable_reg);
+ value |= 0x100; /* stop clock */
+ value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
+ __raw_writel(value, clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_div6_clk_ops = {
+ .recalc = sh_clk_div6_recalc,
+ .round_rate = sh_clk_div_round_rate,
+ .set_rate = sh_clk_div6_set_rate,
+ .enable = sh_clk_div6_enable,
+ .disable = sh_clk_div6_disable,
+};
+
+int __init sh_clk_div6_register(struct clk *clks, int nr)
+{
+ struct clk *clkp;
+ void *freq_table;
+ int nr_divs = sh_clk_div6_table.nr_divisors;
+ int freq_table_size = sizeof(struct cpufreq_frequency_table);
+ int ret = 0;
+ int k;
+
+ freq_table_size *= (nr_divs + 1);
+ freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+ if (!freq_table) {
+ pr_err("sh_clk_div6_register: unable to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+
+ clkp->ops = &sh_clk_div6_clk_ops;
+ clkp->id = -1;
+ clkp->freq_table = freq_table + (k * freq_table_size);
+ clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+ ret = clk_register(clkp);
+ }
+
+ return ret;
+}
+
+static unsigned long sh_clk_div4_recalc(struct clk *clk)
+{
+ struct clk_div4_table *d4t = clk->priv;
+ struct clk_div_mult_table *table = d4t->div_mult_table;
+ unsigned int idx;
+
+ clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+ table, &clk->arch_flags);
+
+ idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
+
+ return clk->freq_table[idx].frequency;
+}
+
+static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_div4_table *d4t = clk->priv;
+ struct clk_div_mult_table *table = d4t->div_mult_table;
+ u32 value;
+ int ret;
+
+ /* we really need a better way to determine parent index, but for
+ * now assume internal parent comes with CLK_ENABLE_ON_INIT set,
+ * no CLK_ENABLE_ON_INIT means external clock...
+ */
+
+ if (parent->flags & CLK_ENABLE_ON_INIT)
+ value = __raw_readl(clk->enable_reg) & ~(1 << 7);
+ else
+ value = __raw_readl(clk->enable_reg) | (1 << 7);
+
+ ret = clk_reparent(clk, parent);
+ if (ret < 0)
+ return ret;
+
+ __raw_writel(value, clk->enable_reg);
+
+ /* Rebiuld the frequency table */
+ clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
+ table, &clk->arch_flags);
+
+ return 0;
+}
+
+static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+ struct clk_div4_table *d4t = clk->priv;
+ unsigned long value;
+ int idx = clk_rate_table_find(clk, clk->freq_table, rate);
+ if (idx < 0)
+ return idx;
+
+ value = __raw_readl(clk->enable_reg);
+ value &= ~(0xf << clk->enable_bit);
+ value |= (idx << clk->enable_bit);
+ __raw_writel(value, clk->enable_reg);
+
+ if (d4t->kick)
+ d4t->kick(clk);
+
+ return 0;
+}
+
+static int sh_clk_div4_enable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg);
+ return 0;
+}
+
+static void sh_clk_div4_disable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg);
+}
+
+static struct clk_ops sh_clk_div4_clk_ops = {
+ .recalc = sh_clk_div4_recalc,
+ .set_rate = sh_clk_div4_set_rate,
+ .round_rate = sh_clk_div_round_rate,
+};
+
+static struct clk_ops sh_clk_div4_enable_clk_ops = {
+ .recalc = sh_clk_div4_recalc,
+ .set_rate = sh_clk_div4_set_rate,
+ .round_rate = sh_clk_div_round_rate,
+ .enable = sh_clk_div4_enable,
+ .disable = sh_clk_div4_disable,
+};
+
+static struct clk_ops sh_clk_div4_reparent_clk_ops = {
+ .recalc = sh_clk_div4_recalc,
+ .set_rate = sh_clk_div4_set_rate,
+ .round_rate = sh_clk_div_round_rate,
+ .enable = sh_clk_div4_enable,
+ .disable = sh_clk_div4_disable,
+ .set_parent = sh_clk_div4_set_parent,
+};
+
+static int __init sh_clk_div4_register_ops(struct clk *clks, int nr,
+ struct clk_div4_table *table, struct clk_ops *ops)
+{
+ struct clk *clkp;
+ void *freq_table;
+ int nr_divs = table->div_mult_table->nr_divisors;
+ int freq_table_size = sizeof(struct cpufreq_frequency_table);
+ int ret = 0;
+ int k;
+
+ freq_table_size *= (nr_divs + 1);
+ freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+ if (!freq_table) {
+ pr_err("sh_clk_div4_register: unable to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+
+ clkp->ops = ops;
+ clkp->id = -1;
+ clkp->priv = table;
+
+ clkp->freq_table = freq_table + (k * freq_table_size);
+ clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
+
+ ret = clk_register(clkp);
+ }
+
+ return ret;
+}
+
+int __init sh_clk_div4_register(struct clk *clks, int nr,
+ struct clk_div4_table *table)
+{
+ return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops);
+}
+
+int __init sh_clk_div4_enable_register(struct clk *clks, int nr,
+ struct clk_div4_table *table)
+{
+ return sh_clk_div4_register_ops(clks, nr, table,
+ &sh_clk_div4_enable_clk_ops);
+}
+
+int __init sh_clk_div4_reparent_register(struct clk *clks, int nr,
+ struct clk_div4_table *table)
+{
+ return sh_clk_div4_register_ops(clks, nr, table,
+ &sh_clk_div4_reparent_clk_ops);
+}
diff --git a/drivers/sh/clk.c b/drivers/sh/clk.c
new file mode 100644
index 000000000000..5d84adac9ec4
--- /dev/null
+++ b/drivers/sh/clk.c
@@ -0,0 +1,545 @@
+/*
+ * drivers/sh/clk.c - SuperH clock framework
+ *
+ * Copyright (C) 2005 - 2009 Paul Mundt
+ *
+ * This clock framework is derived from the OMAP version by:
+ *
+ * Copyright (C) 2004 - 2008 Nokia Corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *
+ * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/cpufreq.h>
+#include <linux/clk.h>
+#include <linux/sh_clk.h>
+
+static LIST_HEAD(clock_list);
+static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(clock_list_sem);
+
+void clk_rate_table_build(struct clk *clk,
+ struct cpufreq_frequency_table *freq_table,
+ int nr_freqs,
+ struct clk_div_mult_table *src_table,
+ unsigned long *bitmap)
+{
+ unsigned long mult, div;
+ unsigned long freq;
+ int i;
+
+ for (i = 0; i < nr_freqs; i++) {
+ div = 1;
+ mult = 1;
+
+ if (src_table->divisors && i < src_table->nr_divisors)
+ div = src_table->divisors[i];
+
+ if (src_table->multipliers && i < src_table->nr_multipliers)
+ mult = src_table->multipliers[i];
+
+ if (!div || !mult || (bitmap && !test_bit(i, bitmap)))
+ freq = CPUFREQ_ENTRY_INVALID;
+ else
+ freq = clk->parent->rate * mult / div;
+
+ freq_table[i].index = i;
+ freq_table[i].frequency = freq;
+ }
+
+ /* Termination entry */
+ freq_table[i].index = i;
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+}
+
+long clk_rate_table_round(struct clk *clk,
+ struct cpufreq_frequency_table *freq_table,
+ unsigned long rate)
+{
+ unsigned long rate_error, rate_error_prev = ~0UL;
+ unsigned long rate_best_fit = rate;
+ unsigned long highest, lowest;
+ int i;
+
+ highest = lowest = 0;
+
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ unsigned long freq = freq_table[i].frequency;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ if (freq > highest)
+ highest = freq;
+ if (freq < lowest)
+ lowest = freq;
+
+ rate_error = abs(freq - rate);
+ if (rate_error < rate_error_prev) {
+ rate_best_fit = freq;
+ rate_error_prev = rate_error;
+ }
+
+ if (rate_error == 0)
+ break;
+ }
+
+ if (rate >= highest)
+ rate_best_fit = highest;
+ if (rate <= lowest)
+ rate_best_fit = lowest;
+
+ return rate_best_fit;
+}
+
+int clk_rate_table_find(struct clk *clk,
+ struct cpufreq_frequency_table *freq_table,
+ unsigned long rate)
+{
+ int i;
+
+ for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+ unsigned long freq = freq_table[i].frequency;
+
+ if (freq == CPUFREQ_ENTRY_INVALID)
+ continue;
+
+ if (freq == rate)
+ return i;
+ }
+
+ return -ENOENT;
+}
+
+/* Used for clocks that always have same value as the parent clock */
+unsigned long followparent_recalc(struct clk *clk)
+{
+ return clk->parent ? clk->parent->rate : 0;
+}
+
+int clk_reparent(struct clk *child, struct clk *parent)
+{
+ list_del_init(&child->sibling);
+ if (parent)
+ list_add(&child->sibling, &parent->children);
+ child->parent = parent;
+
+ /* now do the debugfs renaming to reattach the child
+ to the proper parent */
+
+ return 0;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct clk *tclk)
+{
+ struct clk *clkp;
+
+ list_for_each_entry(clkp, &tclk->children, sibling) {
+ if (clkp->ops && clkp->ops->recalc)
+ clkp->rate = clkp->ops->recalc(clkp);
+
+ propagate_rate(clkp);
+ }
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (WARN(!clk->usecount, "Trying to disable clock %s with 0 usecount\n",
+ clk->name))
+ return;
+
+ if (!(--clk->usecount)) {
+ if (likely(clk->ops && clk->ops->disable))
+ clk->ops->disable(clk);
+ if (likely(clk->parent))
+ __clk_disable(clk->parent);
+ }
+}
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk)
+ return;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clock_lock, flags);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+static int __clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (clk->usecount++ == 0) {
+ if (clk->parent) {
+ ret = __clk_enable(clk->parent);
+ if (unlikely(ret))
+ goto err;
+ }
+
+ if (clk->ops && clk->ops->enable) {
+ ret = clk->ops->enable(clk);
+ if (ret) {
+ if (clk->parent)
+ __clk_disable(clk->parent);
+ goto err;
+ }
+ }
+ }
+
+ return ret;
+err:
+ clk->usecount--;
+ return ret;
+}
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret;
+
+ if (!clk)
+ return -EINVAL;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ ret = __clk_enable(clk);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+static LIST_HEAD(root_clks);
+
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+void recalculate_root_clocks(void)
+{
+ struct clk *clkp;
+
+ list_for_each_entry(clkp, &root_clks, sibling) {
+ if (clkp->ops && clkp->ops->recalc)
+ clkp->rate = clkp->ops->recalc(clkp);
+ propagate_rate(clkp);
+ }
+}
+
+int clk_register(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ /*
+ * trap out already registered clocks
+ */
+ if (clk->node.next || clk->node.prev)
+ return 0;
+
+ mutex_lock(&clock_list_sem);
+
+ INIT_LIST_HEAD(&clk->children);
+ clk->usecount = 0;
+
+ if (clk->parent)
+ list_add(&clk->sibling, &clk->parent->children);
+ else
+ list_add(&clk->sibling, &root_clks);
+
+ list_add(&clk->node, &clock_list);
+ if (clk->ops && clk->ops->init)
+ clk->ops->init(clk);
+ mutex_unlock(&clock_list_sem);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ mutex_lock(&clock_list_sem);
+ list_del(&clk->sibling);
+ list_del(&clk->node);
+ mutex_unlock(&clock_list_sem);
+}
+EXPORT_SYMBOL_GPL(clk_unregister);
+
+void clk_enable_init_clocks(void)
+{
+ struct clk *clkp;
+
+ list_for_each_entry(clkp, &clock_list, node)
+ if (clkp->flags & CLK_ENABLE_ON_INIT)
+ clk_enable(clkp);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
+ int ret = -EOPNOTSUPP;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_lock, flags);
+
+ if (likely(clk->ops && clk->ops->set_rate)) {
+ ret = clk->ops->set_rate(clk, rate, algo_id);
+ if (ret != 0)
+ goto out_unlock;
+ } else {
+ clk->rate = rate;
+ ret = 0;
+ }
+
+ if (clk->ops && clk->ops->recalc)
+ clk->rate = clk->ops->recalc(clk);
+
+ propagate_rate(clk);
+
+out_unlock:
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ if (!parent || !clk)
+ return ret;
+ if (clk->parent == parent)
+ return 0;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ if (clk->usecount == 0) {
+ if (clk->ops->set_parent)
+ ret = clk->ops->set_parent(clk, parent);
+ else
+ ret = clk_reparent(clk, parent);
+
+ if (ret == 0) {
+ pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
+ clk->name, clk->parent->name, clk->rate);
+ if (clk->ops->recalc)
+ clk->rate = clk->ops->recalc(clk);
+ propagate_rate(clk);
+ }
+ } else
+ ret = -EBUSY;
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (likely(clk->ops && clk->ops->round_rate)) {
+ unsigned long flags, rounded;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ rounded = clk->ops->round_rate(clk, rate);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return rounded;
+ }
+
+ return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+#ifdef CONFIG_PM
+static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
+{
+ static pm_message_t prev_state;
+ struct clk *clkp;
+
+ switch (state.event) {
+ case PM_EVENT_ON:
+ /* Resumeing from hibernation */
+ if (prev_state.event != PM_EVENT_FREEZE)
+ break;
+
+ list_for_each_entry(clkp, &clock_list, node) {
+ if (likely(clkp->ops)) {
+ unsigned long rate = clkp->rate;
+
+ if (likely(clkp->ops->set_parent))
+ clkp->ops->set_parent(clkp,
+ clkp->parent);
+ if (likely(clkp->ops->set_rate))
+ clkp->ops->set_rate(clkp,
+ rate, NO_CHANGE);
+ else if (likely(clkp->ops->recalc))
+ clkp->rate = clkp->ops->recalc(clkp);
+ }
+ }
+ break;
+ case PM_EVENT_FREEZE:
+ break;
+ case PM_EVENT_SUSPEND:
+ break;
+ }
+
+ prev_state = state;
+ return 0;
+}
+
+static int clks_sysdev_resume(struct sys_device *dev)
+{
+ return clks_sysdev_suspend(dev, PMSG_ON);
+}
+
+static struct sysdev_class clks_sysdev_class = {
+ .name = "clks",
+};
+
+static struct sysdev_driver clks_sysdev_driver = {
+ .suspend = clks_sysdev_suspend,
+ .resume = clks_sysdev_resume,
+};
+
+static struct sys_device clks_sysdev_dev = {
+ .cls = &clks_sysdev_class,
+};
+
+static int __init clk_sysdev_init(void)
+{
+ sysdev_class_register(&clks_sysdev_class);
+ sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
+ sysdev_register(&clks_sysdev_dev);
+
+ return 0;
+}
+subsys_initcall(clk_sysdev_init);
+#endif
+
+/*
+ * debugfs support to trace clock tree hierarchy and attributes
+ */
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+ int err;
+ struct dentry *d, *child, *child_tmp;
+ struct clk *pa = c->parent;
+ char s[255];
+ char *p = s;
+
+ p += sprintf(p, "%s", c->name);
+ if (c->id >= 0)
+ sprintf(p, ":%d", c->id);
+ d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root);
+ if (!d)
+ return -ENOMEM;
+ c->dentry = d;
+
+ d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount);
+ if (!d) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate);
+ if (!d) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags);
+ if (!d) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ d = c->dentry;
+ list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(c->dentry);
+ return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+ int err;
+ struct clk *pa = c->parent;
+
+ if (pa && !pa->dentry) {
+ err = clk_debugfs_register(pa);
+ if (err)
+ return err;
+ }
+
+ if (!c->dentry && c->name) {
+ err = clk_debugfs_register_one(c);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+ struct clk *c;
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("clock", NULL);
+ if (!d)
+ return -ENOMEM;
+ clk_debugfs_root = d;
+
+ list_for_each_entry(c, &clock_list, node) {
+ err = clk_debugfs_register(c);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+err_out:
+ debugfs_remove_recursive(clk_debugfs_root);
+ return err;
+}
+late_initcall(clk_debugfs_init);
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 94ad6bd86a00..c585574b9aed 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -28,6 +28,7 @@
#include <linux/topology.h>
#include <linux/bitmap.h>
#include <linux/cpumask.h>
+#include <asm/sizes.h>
#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
@@ -45,6 +46,12 @@ struct intc_handle_int {
unsigned long handle;
};
+struct intc_window {
+ phys_addr_t phys;
+ void __iomem *virt;
+ unsigned long size;
+};
+
struct intc_desc_int {
struct list_head list;
struct sys_device sysdev;
@@ -58,6 +65,8 @@ struct intc_desc_int {
unsigned int nr_prio;
struct intc_handle_int *sense;
unsigned int nr_sense;
+ struct intc_window *window;
+ unsigned int nr_windows;
struct irq_chip chip;
};
@@ -87,8 +96,12 @@ static DEFINE_SPINLOCK(vector_lock);
#define SMP_NR(d, x) 1
#endif
-static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+static unsigned int intc_prio_level[NR_IRQS]; /* for now */
+static unsigned int default_prio_level = 2; /* 2 - 16 */
static unsigned long ack_handle[NR_IRQS];
+#ifdef CONFIG_INTC_BALANCING
+static unsigned long dist_handle[NR_IRQS];
+#endif
static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
{
@@ -96,6 +109,47 @@ static inline struct intc_desc_int *get_intc_desc(unsigned int irq)
return container_of(chip, struct intc_desc_int, chip);
}
+static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
+ unsigned long address)
+{
+ struct intc_window *window;
+ int k;
+
+ /* scan through physical windows and convert address */
+ for (k = 0; k < d->nr_windows; k++) {
+ window = d->window + k;
+
+ if (address < window->phys)
+ continue;
+
+ if (address >= (window->phys + window->size))
+ continue;
+
+ address -= window->phys;
+ address += (unsigned long)window->virt;
+
+ return address;
+ }
+
+ /* no windows defined, register must be 1:1 mapped virt:phys */
+ return address;
+}
+
+static unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
+{
+ unsigned int k;
+
+ address = intc_phys_to_virt(d, address);
+
+ for (k = 0; k < d->nr_reg; k++) {
+ if (d->reg[k] == address)
+ return k;
+ }
+
+ BUG();
+ return 0;
+}
+
static inline unsigned int set_field(unsigned int value,
unsigned int field_value,
unsigned int handle)
@@ -229,6 +283,85 @@ static void (*intc_disable_fns[])(unsigned long addr,
[MODE_PCLR_REG] = intc_mode_field,
};
+#ifdef CONFIG_INTC_BALANCING
+static inline void intc_balancing_enable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 1);
+}
+
+static inline void intc_balancing_disable(unsigned int irq)
+{
+ struct intc_desc_int *d = get_intc_desc(irq);
+ unsigned long handle = dist_handle[irq];
+ unsigned long addr;
+
+ if (irq_balancing_disabled(irq) || !handle)
+ return;
+
+ addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
+ intc_reg_fns[_INTC_FN(handle)](addr, handle, 0);
+}
+
+static unsigned int intc_dist_data(struct intc_desc *desc,
+ struct intc_desc_int *d,
+ intc_enum enum_id)
+{
+ struct intc_mask_reg *mr = desc->hw.mask_regs;
+ unsigned int i, j, fn, mode;
+ unsigned long reg_e, reg_d;
+
+ for (i = 0; mr && enum_id && i < desc->hw.nr_mask_regs; i++) {
+ mr = desc->hw.mask_regs + i;
+
+ /*
+ * Skip this entry if there's no auto-distribution
+ * register associated with it.
+ */
+ if (!mr->dist_reg)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = REG_FN_MODIFY_BASE;
+ mode = MODE_ENABLE_REG;
+ reg_e = mr->dist_reg;
+ reg_d = mr->dist_reg;
+
+ fn += (mr->reg_width >> 3) - 1;
+ return _INTC_MK(fn, mode,
+ intc_get_reg(d, reg_e),
+ intc_get_reg(d, reg_d),
+ 1,
+ (mr->reg_width - 1) - j);
+ }
+ }
+
+ /*
+ * It's possible we've gotten here with no distribution options
+ * available for the IRQ in question, so we just skip over those.
+ */
+ return 0;
+}
+#else
+static inline void intc_balancing_enable(unsigned int irq)
+{
+}
+
+static inline void intc_balancing_disable(unsigned int irq)
+{
+}
+#endif
+
static inline void _intc_enable(unsigned int irq, unsigned long handle)
{
struct intc_desc_int *d = get_intc_desc(irq);
@@ -244,6 +377,8 @@ static inline void _intc_enable(unsigned int irq, unsigned long handle)
intc_enable_fns[_INTC_MODE(handle)](addr, handle, intc_reg_fns\
[_INTC_FN(handle)], irq);
}
+
+ intc_balancing_enable(irq);
}
static void intc_enable(unsigned int irq)
@@ -254,10 +389,12 @@ static void intc_enable(unsigned int irq)
static void intc_disable(unsigned int irq)
{
struct intc_desc_int *d = get_intc_desc(irq);
- unsigned long handle = (unsigned long) get_irq_chip_data(irq);
+ unsigned long handle = (unsigned long)get_irq_chip_data(irq);
unsigned long addr;
unsigned int cpu;
+ intc_balancing_disable(irq);
+
for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) {
#ifdef CONFIG_SMP
if (!cpumask_test_cpu(cpu, irq_to_desc(irq)->affinity))
@@ -336,8 +473,7 @@ static void intc_mask_ack(unsigned int irq)
intc_disable(irq);
- /* read register and write zero only to the assocaited bit */
-
+ /* read register and write zero only to the associated bit */
if (handle) {
addr = INTC_REG(d, _INTC_ADDR_D(handle), 0);
switch (_INTC_FN(handle)) {
@@ -366,7 +502,8 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
{
int i;
- /* this doesn't scale well, but...
+ /*
+ * this doesn't scale well, but...
*
* this function should only be used for cerain uncommon
* operations such as intc_set_priority() and intc_set_sense()
@@ -377,7 +514,6 @@ static struct intc_handle_int *intc_find_irq(struct intc_handle_int *hp,
* memory footprint down is to make sure the array is sorted
* and then perform a bisect to lookup the irq.
*/
-
for (i = 0; i < nr_hp; i++) {
if ((hp + i)->irq != irq)
continue;
@@ -408,7 +544,6 @@ int intc_set_priority(unsigned int irq, unsigned int prio)
* primary masking method is using intc_prio_level[irq]
* priority level will be set during next enable()
*/
-
if (_INTC_FN(ihp->handle) != REG_FN_ERR)
_intc_enable(irq, ihp->handle);
}
@@ -447,20 +582,6 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
return 0;
}
-static unsigned int __init intc_get_reg(struct intc_desc_int *d,
- unsigned long address)
-{
- unsigned int k;
-
- for (k = 0; k < d->nr_reg; k++) {
- if (d->reg[k] == address)
- return k;
- }
-
- BUG();
- return 0;
-}
-
static intc_enum __init intc_grp_id(struct intc_desc *desc,
intc_enum enum_id)
{
@@ -718,13 +839,14 @@ static void __init intc_register_irq(struct intc_desc *desc,
*/
set_bit(irq, intc_irq_map);
- /* Prefer single interrupt source bitmap over other combinations:
+ /*
+ * Prefer single interrupt source bitmap over other combinations:
+ *
* 1. bitmap, single interrupt source
* 2. priority, single interrupt source
* 3. bitmap, multiple interrupt sources (groups)
* 4. priority, multiple interrupt sources (groups)
*/
-
data[0] = intc_mask_data(desc, d, enum_id, 0);
data[1] = intc_prio_data(desc, d, enum_id, 0);
@@ -749,10 +871,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
handle_level_irq, "level");
set_irq_chip_data(irq, (void *)data[primary]);
- /* set priority level
+ /*
+ * set priority level
* - this needs to be at least 2 for 5-bit priorities on 7780
*/
- intc_prio_level[irq] = 2;
+ intc_prio_level[irq] = default_prio_level;
/* enable secondary masking method if present */
if (data[!primary])
@@ -769,7 +892,6 @@ static void __init intc_register_irq(struct intc_desc *desc,
* only secondary priority should access registers, so
* set _INTC_FN(h) = REG_FN_ERR for intc_set_priority()
*/
-
hp->handle &= ~_INTC_MK(0x0f, 0, 0, 0, 0, 0);
hp->handle |= _INTC_MK(REG_FN_ERR, 0, 0, 0, 0, 0);
}
@@ -790,6 +912,11 @@ static void __init intc_register_irq(struct intc_desc *desc,
if (desc->hw.ack_regs)
ack_handle[irq] = intc_ack_data(desc, d, enum_id);
+#ifdef CONFIG_INTC_BALANCING
+ if (desc->hw.mask_regs)
+ dist_handle[irq] = intc_dist_data(desc, d, enum_id);
+#endif
+
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID); /* Enable IRQ on ARM systems */
#endif
@@ -801,6 +928,8 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
unsigned int smp)
{
if (value) {
+ value = intc_phys_to_virt(d, value);
+
d->reg[cnt] = value;
#ifdef CONFIG_SMP
d->smp[cnt] = smp;
@@ -816,25 +945,59 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq((unsigned int)get_irq_data(irq));
}
-void __init register_intc_controller(struct intc_desc *desc)
+int __init register_intc_controller(struct intc_desc *desc)
{
unsigned int i, k, smp;
struct intc_hw_desc *hw = &desc->hw;
struct intc_desc_int *d;
+ struct resource *res;
+
+ pr_info("intc: Registered controller '%s' with %u IRQs\n",
+ desc->name, hw->nr_vectors);
d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ if (!d)
+ goto err0;
INIT_LIST_HEAD(&d->list);
list_add(&d->list, &intc_list);
+ if (desc->num_resources) {
+ d->nr_windows = desc->num_resources;
+ d->window = kzalloc(d->nr_windows * sizeof(*d->window),
+ GFP_NOWAIT);
+ if (!d->window)
+ goto err1;
+
+ for (k = 0; k < d->nr_windows; k++) {
+ res = desc->resource + k;
+ WARN_ON(resource_type(res) != IORESOURCE_MEM);
+ d->window[k].phys = res->start;
+ d->window[k].size = resource_size(res);
+ d->window[k].virt = ioremap_nocache(res->start,
+ resource_size(res));
+ if (!d->window[k].virt)
+ goto err2;
+ }
+ }
+
d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
+#ifdef CONFIG_INTC_BALANCING
+ if (d->nr_reg)
+ d->nr_reg += hw->nr_mask_regs;
+#endif
d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
+ if (!d->reg)
+ goto err2;
+
#ifdef CONFIG_SMP
d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
+ if (!d->smp)
+ goto err3;
#endif
k = 0;
@@ -843,12 +1006,17 @@ void __init register_intc_controller(struct intc_desc *desc)
smp = IS_SMP(hw->mask_regs[i]);
k += save_reg(d, k, hw->mask_regs[i].set_reg, smp);
k += save_reg(d, k, hw->mask_regs[i].clr_reg, smp);
+#ifdef CONFIG_INTC_BALANCING
+ k += save_reg(d, k, hw->mask_regs[i].dist_reg, 0);
+#endif
}
}
if (hw->prio_regs) {
d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
GFP_NOWAIT);
+ if (!d->prio)
+ goto err4;
for (i = 0; i < hw->nr_prio_regs; i++) {
smp = IS_SMP(hw->prio_regs[i]);
@@ -860,6 +1028,8 @@ void __init register_intc_controller(struct intc_desc *desc)
if (hw->sense_regs) {
d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
GFP_NOWAIT);
+ if (!d->sense)
+ goto err5;
for (i = 0; i < hw->nr_sense_regs; i++)
k += save_reg(d, k, hw->sense_regs[i].reg, 0);
@@ -906,7 +1076,7 @@ void __init register_intc_controller(struct intc_desc *desc)
irq_desc = irq_to_desc_alloc_node(irq, numa_node_id());
if (unlikely(!irq_desc)) {
- pr_info("can't get irq_desc for %d\n", irq);
+ pr_err("can't get irq_desc for %d\n", irq);
continue;
}
@@ -926,7 +1096,7 @@ void __init register_intc_controller(struct intc_desc *desc)
*/
irq_desc = irq_to_desc_alloc_node(irq2, numa_node_id());
if (unlikely(!irq_desc)) {
- pr_info("can't get irq_desc for %d\n", irq2);
+ pr_err("can't get irq_desc for %d\n", irq2);
continue;
}
@@ -942,8 +1112,100 @@ void __init register_intc_controller(struct intc_desc *desc)
/* enable bits matching force_enable after registering irqs */
if (desc->force_enable)
intc_enable_disable_enum(desc, d, desc->force_enable, 1);
+
+ return 0;
+err5:
+ kfree(d->prio);
+err4:
+#ifdef CONFIG_SMP
+ kfree(d->smp);
+err3:
+#endif
+ kfree(d->reg);
+err2:
+ for (k = 0; k < d->nr_windows; k++)
+ if (d->window[k].virt)
+ iounmap(d->window[k].virt);
+
+ kfree(d->window);
+err1:
+ kfree(d);
+err0:
+ pr_err("unable to allocate INTC memory\n");
+
+ return -ENOMEM;
+}
+
+#ifdef CONFIG_INTC_USERIMASK
+static void __iomem *uimask;
+
+int register_intc_userimask(unsigned long addr)
+{
+ if (unlikely(uimask))
+ return -EBUSY;
+
+ uimask = ioremap_nocache(addr, SZ_4K);
+ if (unlikely(!uimask))
+ return -ENOMEM;
+
+ pr_info("intc: userimask support registered for levels 0 -> %d\n",
+ default_prio_level - 1);
+
+ return 0;
+}
+
+static ssize_t
+show_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", (__raw_readl(uimask) >> 4) & 0xf);
+}
+
+static ssize_t
+store_intc_userimask(struct sysdev_class *cls,
+ struct sysdev_class_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long level;
+
+ level = simple_strtoul(buf, NULL, 10);
+
+ /*
+ * Minimal acceptable IRQ levels are in the 2 - 16 range, but
+ * these are chomped so as to not interfere with normal IRQs.
+ *
+ * Level 1 is a special case on some CPUs in that it's not
+ * directly settable, but given that USERIMASK cuts off below a
+ * certain level, we don't care about this limitation here.
+ * Level 0 on the other hand equates to user masking disabled.
+ *
+ * We use default_prio_level as a cut off so that only special
+ * case opt-in IRQs can be mangled.
+ */
+ if (level >= default_prio_level)
+ return -EINVAL;
+
+ __raw_writel(0xa5 << 24 | level << 4, uimask);
+
+ return count;
}
+static SYSDEV_CLASS_ATTR(userimask, S_IRUSR | S_IWUSR,
+ show_intc_userimask, store_intc_userimask);
+#endif
+
+static ssize_t
+show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf)
+{
+ struct intc_desc_int *d;
+
+ d = container_of(dev, struct intc_desc_int, sysdev);
+
+ return sprintf(buf, "%s\n", d->chip.name);
+}
+
+static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
+
static int intc_suspend(struct sys_device *dev, pm_message_t state)
{
struct intc_desc_int *d;
@@ -1003,19 +1265,28 @@ static int __init register_intc_sysdevs(void)
int id = 0;
error = sysdev_class_register(&intc_sysdev_class);
+#ifdef CONFIG_INTC_USERIMASK
+ if (!error && uimask)
+ error = sysdev_class_create_file(&intc_sysdev_class,
+ &attr_userimask);
+#endif
if (!error) {
list_for_each_entry(d, &intc_list, list) {
d->sysdev.id = id;
d->sysdev.cls = &intc_sysdev_class;
error = sysdev_register(&d->sysdev);
+ if (error == 0)
+ error = sysdev_create_file(&d->sysdev,
+ &attr_name);
if (error)
break;
+
id++;
}
}
if (error)
- pr_warning("intc: sysdev registration error\n");
+ pr_err("intc: sysdev registration error\n");
return error;
}
@@ -1048,7 +1319,7 @@ unsigned int create_irq_nr(unsigned int irq_want, int node)
desc = irq_to_desc_alloc_node(new, node);
if (unlikely(!desc)) {
- pr_info("can't get irq_desc for %d\n", new);
+ pr_err("can't get irq_desc for %d\n", new);
goto out_unlock;
}
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 36828358a4d8..e76b1afafe07 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -36,8 +36,7 @@
#include <asm/delay.h>
#include <mach/dma.h>
-#include <mach/regs-ssp.h>
-#include <mach/ssp.h>
+#include <plat/ssp.h>
#include <mach/pxa2xx_spi.h>
MODULE_AUTHOR("Stephen Street");
@@ -1318,14 +1317,14 @@ static int setup(struct spi_device *spi)
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP)
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
- clk_get_rate(ssp->clk)
- / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
+ clk_get_rate(ssp->clk)
+ / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
+ chip->enable_dma ? "DMA" : "PIO");
else
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
- clk_get_rate(ssp->clk) / 2
- / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
+ clk_get_rate(ssp->clk) / 2
+ / (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
+ chip->enable_dma ? "DMA" : "PIO");
if (spi->bits_per_word <= 8) {
chip->n_bytes = 1;
@@ -1466,7 +1465,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
platform_info = dev->platform_data;
- ssp = ssp_request(pdev->id, pdev->name);
+ ssp = pxa_ssp_request(pdev->id, pdev->name);
if (ssp == NULL) {
dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id);
return -ENODEV;
@@ -1476,7 +1475,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) {
dev_err(&pdev->dev, "cannot alloc spi_master\n");
- ssp_free(ssp);
+ pxa_ssp_free(ssp);
return -ENOMEM;
}
drv_data = spi_master_get_devdata(master);
@@ -1558,7 +1557,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
SSCR1_TxTresh(TX_THRESH_DFLT),
drv_data->ioaddr);
- write_SSCR0(SSCR0_SerClkDiv(2)
+ write_SSCR0(SSCR0_SCR(2)
| SSCR0_Motorola
| SSCR0_DataSize(8),
drv_data->ioaddr);
@@ -1605,7 +1604,7 @@ out_error_irq_alloc:
out_error_master_alloc:
spi_master_put(master);
- ssp_free(ssp);
+ pxa_ssp_free(ssp);
return status;
}
@@ -1649,7 +1648,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
free_irq(ssp->irq, drv_data);
/* Release SSP */
- ssp_free(ssp);
+ pxa_ssp_free(ssp);
/* Disconnect from the SPI framework */
spi_unregister_master(drv_data->master);
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 4a6366a42129..111a01a747fc 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -380,6 +380,7 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
mutex_lock(&inode->i_mutex);
dentry_unhash(dentry);
if (usbfs_empty(dentry)) {
+ dont_mount(dentry);
drop_nlink(dentry->d_inode);
drop_nlink(dentry->d_inode);
dput(dentry);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index df1bae9b048e..eaa79c8a9b8c 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -366,6 +366,13 @@ rescan:
if (is_done)
done(ep, req, 0);
else if (ep->is_pingpong) {
+ /*
+ * One dummy read to delay the code because of a HW glitch:
+ * CSR returns bad RXCOUNT when read too soon after updating
+ * RX_DATA_BK flags.
+ */
+ csr = __raw_readl(creg);
+
bufferspace -= count;
buf += count;
goto rescan;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index e69d238c5af0..49fa953aaf6e 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1035,7 +1035,12 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
/* This actually signals the guest, using eventfd. */
void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
- __u16 flags = 0;
+ __u16 flags;
+ /* Flush out used index updates. This is paired
+ * with the barrier that the Guest executes when enabling
+ * interrupts. */
+ smp_mb();
+
if (get_user(flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return;
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index dca48df98444..e5d6b56d4447 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -50,8 +50,9 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
-
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
+
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
@@ -1135,7 +1136,7 @@ static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
* Interface to the low level console driver
*/
-static void amifb_deinit(void);
+static void amifb_deinit(struct platform_device *pdev);
/*
* Internal routines
@@ -2246,7 +2247,7 @@ static inline void chipfree(void)
* Initialisation
*/
-static int __init amifb_init(void)
+static int __init amifb_probe(struct platform_device *pdev)
{
int tag, i, err = 0;
u_long chipptr;
@@ -2261,16 +2262,6 @@ static int __init amifb_init(void)
}
amifb_setup(option);
#endif
- if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
- return -ENODEV;
-
- /*
- * We request all registers starting from bplpt[0]
- */
- if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
- "amifb [Denise/Lisa]"))
- return -EBUSY;
-
custom.dmacon = DMAF_ALL | DMAF_MASTER;
switch (amiga_chipset) {
@@ -2377,6 +2368,7 @@ default_chipset:
fb_info.fbops = &amifb_ops;
fb_info.par = &currentpar;
fb_info.flags = FBINFO_DEFAULT;
+ fb_info.device = &pdev->dev;
if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
@@ -2451,18 +2443,18 @@ default_chipset:
return 0;
amifb_error:
- amifb_deinit();
+ amifb_deinit(pdev);
return err;
}
-static void amifb_deinit(void)
+static void amifb_deinit(struct platform_device *pdev)
{
if (fb_info.cmap.len)
fb_dealloc_cmap(&fb_info.cmap);
+ fb_dealloc_cmap(&fb_info.cmap);
chipfree();
if (videomemory)
iounmap((void*)videomemory);
- release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
@@ -3794,14 +3786,35 @@ static void ami_rebuild_copper(void)
}
}
-static void __exit amifb_exit(void)
+static int __exit amifb_remove(struct platform_device *pdev)
{
unregister_framebuffer(&fb_info);
- amifb_deinit();
+ amifb_deinit(pdev);
amifb_video_off();
+ return 0;
+}
+
+static struct platform_driver amifb_driver = {
+ .remove = __exit_p(amifb_remove),
+ .driver = {
+ .name = "amiga-video",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amifb_init(void)
+{
+ return platform_driver_probe(&amifb_driver, amifb_probe);
}
module_init(amifb_init);
+
+static void __exit amifb_exit(void)
+{
+ platform_driver_unregister(&amifb_driver);
+}
+
module_exit(amifb_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-video");
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 44e49c28b2a7..c2ec3dcd4e91 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -488,9 +488,9 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
fbinfo->fbops = &bfin_t350mcqb_fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
- info->fb_buffer =
- dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
- GFP_KERNEL);
+ info->fb_buffer = dma_alloc_coherent(NULL, fbinfo->fix.smem_len +
+ ACTIVE_VIDEO_MEM_OFFSET,
+ &info->dma_handle, GFP_KERNEL);
if (NULL == info->fb_buffer) {
printk(KERN_ERR DRIVER_NAME
@@ -568,8 +568,8 @@ out7:
out6:
fb_dealloc_cmap(&fbinfo->cmap);
out4:
- dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
- info->dma_handle);
+ dma_free_coherent(NULL, fbinfo->fix.smem_len + ACTIVE_VIDEO_MEM_OFFSET,
+ info->fb_buffer, info->dma_handle);
out3:
framebuffer_release(fbinfo);
out2:
@@ -592,8 +592,9 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
free_irq(info->irq, info);
if (info->fb_buffer != NULL)
- dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
- info->dma_handle);
+ dma_free_coherent(NULL, fbinfo->fix.smem_len +
+ ACTIVE_VIDEO_MEM_OFFSET, info->fb_buffer,
+ info->dma_handle);
fb_dealloc_cmap(&fbinfo->cmap);
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 8d8dfda2f868..6df7c54db0a3 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -299,6 +299,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = {
},
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
static const struct {
zorro_id id2;
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index 6c91c61cdb63..1b0feb8e7244 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -219,6 +219,7 @@ static struct zorro_device_id fm2fb_devices[] __devinitdata = {
{ ZORRO_PROD_HELFRICH_RAINBOW_II },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, fm2fb_devices);
static struct zorro_driver fm2fb_driver = {
.name = "fm2fb",
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e14bd0749129..e8c769944812 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -695,6 +695,7 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
* 1) Enable Runtime PM
* 2) Force Runtime PM Resume since hardware is accessed from probe()
*/
+ priv->dev = &pdev->dev;
pm_runtime_enable(priv->dev);
pm_runtime_resume(priv->dev);
return 0;
@@ -957,25 +958,24 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "no platform data defined\n");
- error = -EINVAL;
- goto err0;
+ return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i = platform_get_irq(pdev, 0);
if (!res || i < 0) {
dev_err(&pdev->dev, "cannot get platform resources\n");
- error = -ENOENT;
- goto err0;
+ return -ENOENT;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "cannot allocate device data\n");
- error = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
+ platform_set_drvdata(pdev, priv);
+
error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
dev_name(&pdev->dev), priv);
if (error) {
@@ -984,8 +984,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
}
priv->irq = i;
- priv->dev = &pdev->dev;
- platform_set_drvdata(pdev, priv);
pdata = pdev->dev.platform_data;
j = 0;
@@ -1099,9 +1097,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
info = ch->info;
if (info->fbdefio) {
- priv->ch->sglist = vmalloc(sizeof(struct scatterlist) *
+ ch->sglist = vmalloc(sizeof(struct scatterlist) *
info->fix.smem_len >> PAGE_SHIFT);
- if (!priv->ch->sglist) {
+ if (!ch->sglist) {
dev_err(&pdev->dev, "cannot allocate sglist\n");
goto err1;
}
@@ -1126,9 +1124,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
}
return 0;
- err1:
+err1:
sh_mobile_lcdc_remove(pdev);
- err0:
+
return error;
}
@@ -1139,7 +1137,7 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
int i;
for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
- if (priv->ch[i].info->dev)
+ if (priv->ch[i].info && priv->ch[i].info->dev)
unregister_framebuffer(priv->ch[i].info);
sh_mobile_lcdc_stop(priv);
@@ -1162,7 +1160,8 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
if (priv->dot_clk)
clk_put(priv->dot_clk);
- pm_runtime_disable(priv->dev);
+ if (priv->dev)
+ pm_runtime_disable(priv->dev);
if (priv->base)
iounmap(priv->base);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 0bf5020d0d32..b87ba23442d2 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -175,7 +175,7 @@ config SA1100_WATCHDOG
config MPCORE_WATCHDOG
tristate "MPcore watchdog"
- depends on ARM_MPCORE_PLATFORM && LOCAL_TIMERS
+ depends on HAVE_ARM_TWD
help
Watchdog timer embedded into the MPcore system.
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index 016c6a791cab..b8ec7aca3c8e 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -31,8 +31,9 @@
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
+#include <linux/io.h>
-#include <asm/hardware/arm_twd.h>
+#include <asm/smp_twd.h>
struct mpcore_wdt {
unsigned long timer_alive;
@@ -44,7 +45,7 @@ struct mpcore_wdt {
};
static struct platform_device *mpcore_wdt_dev;
-extern unsigned int mpcore_timer_rate;
+static DEFINE_SPINLOCK(wdt_lock);
#define TIMER_MARGIN 60
static int mpcore_margin = TIMER_MARGIN;
@@ -94,13 +95,15 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
*/
static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
{
- unsigned int count;
+ unsigned long count;
+ spin_lock(&wdt_lock);
/* Assume prescale is set to 256 */
- count = (mpcore_timer_rate / 256) * mpcore_margin;
+ count = __raw_readl(wdt->base + TWD_WDOG_COUNTER);
+ count = (0xFFFFFFFFU - count) * (HZ / 5);
+ count = (count / 256) * mpcore_margin;
/* Reload the counter */
- spin_lock(&wdt_lock);
writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
wdt->perturb = wdt->perturb ? 0 : 1;
spin_unlock(&wdt_lock);
@@ -119,7 +122,6 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt)
{
dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
- spin_lock(&wdt_lock);
/* This loads the count register but does NOT start the count yet */
mpcore_wdt_keepalive(wdt);
@@ -130,7 +132,6 @@ static void mpcore_wdt_start(struct mpcore_wdt *wdt)
/* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
}
- spin_unlock(&wdt_lock);
}
static int mpcore_wdt_set_heartbeat(int t)
@@ -360,7 +361,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
mpcore_wdt_miscdev.parent = &dev->dev;
ret = misc_register(&mpcore_wdt_miscdev);
if (ret) {
- dev_printk(KERN_ERR, _dev,
+ dev_printk(KERN_ERR, wdt->dev,
"cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
goto err_misc;
@@ -369,13 +370,13 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED,
"mpcore_wdt", wdt);
if (ret) {
- dev_printk(KERN_ERR, _dev,
+ dev_printk(KERN_ERR, wdt->dev,
"cannot register IRQ%d for watchdog\n", wdt->irq);
goto err_irq;
}
mpcore_wdt_stop(wdt);
- platform_set_drvdata(&dev->dev, wdt);
+ platform_set_drvdata(dev, wdt);
mpcore_wdt_dev = dev;
return 0;
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index 2ac4440e7b08..8943b8ccee1a 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -80,12 +80,6 @@ static void do_suspend(void)
shutting_down = SHUTDOWN_SUSPEND;
- err = stop_machine_create();
- if (err) {
- printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err);
- goto out;
- }
-
#ifdef CONFIG_PREEMPT
/* If the kernel is preemptible, we need to freeze all the processes
to prevent them from being in the middle of a pagetable update
@@ -93,7 +87,7 @@ static void do_suspend(void)
err = freeze_processes();
if (err) {
printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
- goto out_destroy_sm;
+ goto out;
}
#endif
@@ -136,12 +130,8 @@ out_resume:
out_thaw:
#ifdef CONFIG_PREEMPT
thaw_processes();
-
-out_destroy_sm:
-#endif
- stop_machine_destroy();
-
out:
+#endif
shutting_down = SHUTDOWN_INVALID;
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index d47c47fc048f..3c7046d79654 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -97,7 +97,7 @@ static void zorro_seq_stop(struct seq_file *m, void *v)
static int zorro_seq_show(struct seq_file *m, void *v)
{
- u_int slot = *(loff_t *)v;
+ unsigned int slot = *(loff_t *)v;
struct zorro_dev *z = &zorro_autocon[slot];
seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id,
@@ -129,7 +129,7 @@ static const struct file_operations zorro_devices_proc_fops = {
static struct proc_dir_entry *proc_bus_zorro_dir;
-static int __init zorro_proc_attach_device(u_int slot)
+static int __init zorro_proc_attach_device(unsigned int slot)
{
struct proc_dir_entry *entry;
char name[4];
@@ -146,7 +146,7 @@ static int __init zorro_proc_attach_device(u_int slot)
static int __init zorro_proc_init(void)
{
- u_int slot;
+ unsigned int slot;
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL);
diff --git a/drivers/zorro/zorro-driver.c b/drivers/zorro/zorro-driver.c
index 53180a37cc9a..7ee2b6e71786 100644
--- a/drivers/zorro/zorro-driver.c
+++ b/drivers/zorro/zorro-driver.c
@@ -137,10 +137,34 @@ static int zorro_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
+static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+#ifdef CONFIG_HOTPLUG
+ struct zorro_dev *z;
+
+ if (!dev)
+ return -ENODEV;
+
+ z = to_zorro_dev(dev);
+ if (!z)
+ return -ENODEV;
+
+ if (add_uevent_var(env, "ZORRO_ID=%08X", z->id) ||
+ add_uevent_var(env, "ZORRO_SLOT_NAME=%s", dev_name(dev)) ||
+ add_uevent_var(env, "ZORRO_SLOT_ADDR=%04X", z->slotaddr) ||
+ add_uevent_var(env, "MODALIAS=" ZORRO_DEVICE_MODALIAS_FMT, z->id))
+ return -ENOMEM;
+
+ return 0;
+#else /* !CONFIG_HOTPLUG */
+ return -ENODEV;
+#endif /* !CONFIG_HOTPLUG */
+}
struct bus_type zorro_bus_type = {
.name = "zorro",
.match = zorro_bus_match,
+ .uevent = zorro_uevent,
.probe = zorro_device_probe,
.remove = zorro_device_remove,
};
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 1d2a772ea14c..eb924e0a64ce 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -77,6 +77,16 @@ static struct bin_attribute zorro_config_attr = {
.read = zorro_read_config,
};
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct zorro_dev *z = to_zorro_dev(dev);
+
+ return sprintf(buf, ZORRO_DEVICE_MODALIAS_FMT "\n", z->id);
+}
+
+static DEVICE_ATTR(modalias, S_IRUGO, modalias_show, NULL);
+
int zorro_create_sysfs_dev_files(struct zorro_dev *z)
{
struct device *dev = &z->dev;
@@ -89,6 +99,7 @@ int zorro_create_sysfs_dev_files(struct zorro_dev *z)
(error = device_create_file(dev, &dev_attr_slotaddr)) ||
(error = device_create_file(dev, &dev_attr_slotsize)) ||
(error = device_create_file(dev, &dev_attr_resource)) ||
+ (error = device_create_file(dev, &dev_attr_modalias)) ||
(error = sysfs_create_bin_file(&dev->kobj, &zorro_config_attr)))
return error;
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index d45fb34e2d23..6455f3a244c5 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -15,6 +15,8 @@
#include <linux/zorro.h>
#include <linux/bitops.h>
#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
@@ -26,24 +28,17 @@
* Zorro Expansion Devices
*/
-u_int zorro_num_autocon = 0;
+unsigned int zorro_num_autocon;
struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO];
/*
- * Single Zorro bus
+ * Zorro bus
*/
-struct zorro_bus zorro_bus = {\
- .resources = {
- /* Zorro II regions (on Zorro II/III) */
- { .name = "Zorro II exp", .start = 0x00e80000, .end = 0x00efffff },
- { .name = "Zorro II mem", .start = 0x00200000, .end = 0x009fffff },
- /* Zorro III regions (on Zorro III only) */
- { .name = "Zorro III exp", .start = 0xff000000, .end = 0xffffffff },
- { .name = "Zorro III cfg", .start = 0x40000000, .end = 0x7fffffff }
- },
- .name = "Zorro bus"
+struct zorro_bus {
+ struct list_head devices; /* list of devices on this bus */
+ struct device dev;
};
@@ -53,18 +48,19 @@ struct zorro_bus zorro_bus = {\
struct zorro_dev *zorro_find_device(zorro_id id, struct zorro_dev *from)
{
- struct zorro_dev *z;
+ struct zorro_dev *z;
- if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
- return NULL;
+ if (!zorro_num_autocon)
+ return NULL;
- for (z = from ? from+1 : &zorro_autocon[0];
- z < zorro_autocon+zorro_num_autocon;
- z++)
- if (id == ZORRO_WILDCARD || id == z->id)
- return z;
- return NULL;
+ for (z = from ? from+1 : &zorro_autocon[0];
+ z < zorro_autocon+zorro_num_autocon;
+ z++)
+ if (id == ZORRO_WILDCARD || id == z->id)
+ return z;
+ return NULL;
}
+EXPORT_SYMBOL(zorro_find_device);
/*
@@ -83,121 +79,138 @@ struct zorro_dev *zorro_find_device(zorro_id id, struct zorro_dev *from)
*/
DECLARE_BITMAP(zorro_unused_z2ram, 128);
+EXPORT_SYMBOL(zorro_unused_z2ram);
static void __init mark_region(unsigned long start, unsigned long end,
int flag)
{
- if (flag)
- start += Z2RAM_CHUNKMASK;
- else
- end += Z2RAM_CHUNKMASK;
- start &= ~Z2RAM_CHUNKMASK;
- end &= ~Z2RAM_CHUNKMASK;
-
- if (end <= Z2RAM_START || start >= Z2RAM_END)
- return;
- start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
- end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
- while (start < end) {
- u32 chunk = start>>Z2RAM_CHUNKSHIFT;
if (flag)
- set_bit(chunk, zorro_unused_z2ram);
+ start += Z2RAM_CHUNKMASK;
else
- clear_bit(chunk, zorro_unused_z2ram);
- start += Z2RAM_CHUNKSIZE;
- }
+ end += Z2RAM_CHUNKMASK;
+ start &= ~Z2RAM_CHUNKMASK;
+ end &= ~Z2RAM_CHUNKMASK;
+
+ if (end <= Z2RAM_START || start >= Z2RAM_END)
+ return;
+ start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START;
+ end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START;
+ while (start < end) {
+ u32 chunk = start>>Z2RAM_CHUNKSHIFT;
+ if (flag)
+ set_bit(chunk, zorro_unused_z2ram);
+ else
+ clear_bit(chunk, zorro_unused_z2ram);
+ start += Z2RAM_CHUNKSIZE;
+ }
}
-static struct resource __init *zorro_find_parent_resource(struct zorro_dev *z)
+static struct resource __init *zorro_find_parent_resource(
+ struct platform_device *bridge, struct zorro_dev *z)
{
- int i;
+ int i;
- for (i = 0; i < zorro_bus.num_resources; i++)
- if (zorro_resource_start(z) >= zorro_bus.resources[i].start &&
- zorro_resource_end(z) <= zorro_bus.resources[i].end)
- return &zorro_bus.resources[i];
- return &iomem_resource;
+ for (i = 0; i < bridge->num_resources; i++) {
+ struct resource *r = &bridge->resource[i];
+ if (zorro_resource_start(z) >= r->start &&
+ zorro_resource_end(z) <= r->end)
+ return r;
+ }
+ return &iomem_resource;
}
- /*
- * Initialization
- */
-static int __init zorro_init(void)
+static int __init amiga_zorro_probe(struct platform_device *pdev)
{
- struct zorro_dev *z;
- unsigned int i;
- int error;
-
- if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
- return 0;
-
- pr_info("Zorro: Probing AutoConfig expansion devices: %d device%s\n",
- zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
-
- /* Initialize the Zorro bus */
- INIT_LIST_HEAD(&zorro_bus.devices);
- dev_set_name(&zorro_bus.dev, "zorro");
- error = device_register(&zorro_bus.dev);
- if (error) {
- pr_err("Zorro: Error registering zorro_bus\n");
- return error;
- }
-
- /* Request the resources */
- zorro_bus.num_resources = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2;
- for (i = 0; i < zorro_bus.num_resources; i++)
- request_resource(&iomem_resource, &zorro_bus.resources[i]);
-
- /* Register all devices */
- for (i = 0; i < zorro_num_autocon; i++) {
- z = &zorro_autocon[i];
- z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8);
- if (z->id == ZORRO_PROD_GVP_EPC_BASE) {
- /* GVP quirk */
- unsigned long magic = zorro_resource_start(z)+0x8000;
- z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK;
- }
- sprintf(z->name, "Zorro device %08x", z->id);
- zorro_name_device(z);
- z->resource.name = z->name;
- if (request_resource(zorro_find_parent_resource(z), &z->resource))
- pr_err("Zorro: Address space collision on device %s %pR\n",
- z->name, &z->resource);
- dev_set_name(&z->dev, "%02x", i);
- z->dev.parent = &zorro_bus.dev;
- z->dev.bus = &zorro_bus_type;
- error = device_register(&z->dev);
+ struct zorro_bus *bus;
+ struct zorro_dev *z;
+ struct resource *r;
+ unsigned int i;
+ int error;
+
+ /* Initialize the Zorro bus */
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&bus->devices);
+ bus->dev.parent = &pdev->dev;
+ dev_set_name(&bus->dev, "zorro");
+ error = device_register(&bus->dev);
if (error) {
- pr_err("Zorro: Error registering device %s\n", z->name);
- continue;
+ pr_err("Zorro: Error registering zorro_bus\n");
+ kfree(bus);
+ return error;
}
- error = zorro_create_sysfs_dev_files(z);
- if (error)
- dev_err(&z->dev, "Error creating sysfs files\n");
- }
-
- /* Mark all available Zorro II memory */
- zorro_for_each_dev(z) {
- if (z->rom.er_Type & ERTF_MEMLIST)
- mark_region(zorro_resource_start(z), zorro_resource_end(z)+1, 1);
- }
-
- /* Unmark all used Zorro II memory */
- for (i = 0; i < m68k_num_memory; i++)
- if (m68k_memory[i].addr < 16*1024*1024)
- mark_region(m68k_memory[i].addr,
- m68k_memory[i].addr+m68k_memory[i].size, 0);
-
- return 0;
+ platform_set_drvdata(pdev, bus);
+
+ /* Register all devices */
+ pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n",
+ zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+
+ for (i = 0; i < zorro_num_autocon; i++) {
+ z = &zorro_autocon[i];
+ z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8);
+ if (z->id == ZORRO_PROD_GVP_EPC_BASE) {
+ /* GVP quirk */
+ unsigned long magic = zorro_resource_start(z)+0x8000;
+ z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK;
+ }
+ sprintf(z->name, "Zorro device %08x", z->id);
+ zorro_name_device(z);
+ z->resource.name = z->name;
+ r = zorro_find_parent_resource(pdev, z);
+ error = request_resource(r, &z->resource);
+ if (error)
+ dev_err(&bus->dev,
+ "Address space collision on device %s %pR\n",
+ z->name, &z->resource);
+ dev_set_name(&z->dev, "%02x", i);
+ z->dev.parent = &bus->dev;
+ z->dev.bus = &zorro_bus_type;
+ error = device_register(&z->dev);
+ if (error) {
+ dev_err(&bus->dev, "Error registering device %s\n",
+ z->name);
+ continue;
+ }
+ error = zorro_create_sysfs_dev_files(z);
+ if (error)
+ dev_err(&z->dev, "Error creating sysfs files\n");
+ }
+
+ /* Mark all available Zorro II memory */
+ zorro_for_each_dev(z) {
+ if (z->rom.er_Type & ERTF_MEMLIST)
+ mark_region(zorro_resource_start(z),
+ zorro_resource_end(z)+1, 1);
+ }
+
+ /* Unmark all used Zorro II memory */
+ for (i = 0; i < m68k_num_memory; i++)
+ if (m68k_memory[i].addr < 16*1024*1024)
+ mark_region(m68k_memory[i].addr,
+ m68k_memory[i].addr+m68k_memory[i].size,
+ 0);
+
+ return 0;
}
-subsys_initcall(zorro_init);
+static struct platform_driver amiga_zorro_driver = {
+ .driver = {
+ .name = "amiga-zorro",
+ .owner = THIS_MODULE,
+ },
+};
-EXPORT_SYMBOL(zorro_find_device);
-EXPORT_SYMBOL(zorro_unused_z2ram);
+static int __init amiga_zorro_init(void)
+{
+ return platform_driver_probe(&amiga_zorro_driver, amiga_zorro_probe);
+}
+
+module_init(amiga_zorro_init);
MODULE_LICENSE("GPL");