diff options
Diffstat (limited to 'drivers')
207 files changed, 3401 insertions, 1747 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index a2b902f4d437..3d93b3a3d630 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -111,4 +111,6 @@ source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" source "drivers/platform/Kconfig" + +source "drivers/clk/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index f3ebb30f1b7f..bf15ce7493d2 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -115,3 +115,5 @@ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ obj-y += ieee802154/ +#common clk code +obj-y += clk/ diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 2c7def95f721..4c8dea513b66 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -408,6 +408,9 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } + /* Disable the GPE in case it's been enabled already. */ + (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + /* * Add the GPE information from above to the gpe_event_info block for * use during dispatch of this GPE. diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9fb9d5ac939d..95649d373071 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -130,8 +130,6 @@ struct acpi_battery { unsigned long flags; }; -static int acpi_battery_update(struct acpi_battery *battery); - #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); inline int acpi_battery_present(struct acpi_battery *battery) @@ -186,9 +184,6 @@ static int acpi_battery_get_property(struct power_supply *psy, int ret = 0; struct acpi_battery *battery = to_acpi_battery(psy); - if (acpi_battery_update(battery)) - return -ENODEV; - if (acpi_battery_present(battery)) { /* run battery update only if it is present */ acpi_battery_get_state(battery); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2b6c21d86b98..29ef505c487b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -705,54 +705,85 @@ static int acpi_bus_get_perf_flags(struct acpi_device *device) } static acpi_status -acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, - union acpi_object *package) +acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, + struct acpi_device_wakeup *wakeup) { - int i = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package = NULL; union acpi_object *element = NULL; + acpi_status status; + int i = 0; - if (!device || !package || (package->package.count < 2)) + if (!wakeup) return AE_BAD_PARAMETER; + /* _PRW */ + status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); + return status; + } + + package = (union acpi_object *)buffer.pointer; + + if (!package || (package->package.count < 2)) { + status = AE_BAD_DATA; + goto out; + } + element = &(package->package.elements[0]); - if (!element) - return AE_BAD_PARAMETER; + if (!element) { + status = AE_BAD_DATA; + goto out; + } if (element->type == ACPI_TYPE_PACKAGE) { if ((element->package.count < 2) || (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) - || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) - return AE_BAD_DATA; - device->wakeup.gpe_device = + || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { + status = AE_BAD_DATA; + goto out; + } + wakeup->gpe_device = element->package.elements[0].reference.handle; - device->wakeup.gpe_number = + wakeup->gpe_number = (u32) element->package.elements[1].integer.value; } else if (element->type == ACPI_TYPE_INTEGER) { - device->wakeup.gpe_number = element->integer.value; - } else - return AE_BAD_DATA; + wakeup->gpe_device = NULL; + wakeup->gpe_number = element->integer.value; + } else { + status = AE_BAD_DATA; + goto out; + } element = &(package->package.elements[1]); if (element->type != ACPI_TYPE_INTEGER) { - return AE_BAD_DATA; + status = AE_BAD_DATA; + goto out; } - device->wakeup.sleep_state = element->integer.value; + wakeup->sleep_state = element->integer.value; if ((package->package.count - 2) > ACPI_MAX_HANDLES) { - return AE_NO_MEMORY; + status = AE_NO_MEMORY; + goto out; } - device->wakeup.resources.count = package->package.count - 2; - for (i = 0; i < device->wakeup.resources.count; i++) { + wakeup->resources.count = package->package.count - 2; + for (i = 0; i < wakeup->resources.count; i++) { element = &(package->package.elements[i + 2]); - if (element->type != ACPI_TYPE_LOCAL_REFERENCE) - return AE_BAD_DATA; + if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { + status = AE_BAD_DATA; + goto out; + } - device->wakeup.resources.handles[i] = element->reference.handle; + wakeup->resources.handles[i] = element->reference.handle; } - acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number); + acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number); - return AE_OK; + out: + kfree(buffer.pointer); + + return status; } static void acpi_bus_set_run_wake_flags(struct acpi_device *device) @@ -787,26 +818,15 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { acpi_status status = 0; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *package = NULL; int psw_error; - /* _PRW */ - status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); - goto end; - } - - package = (union acpi_object *)buffer.pointer; - status = acpi_bus_extract_wakeup_device_power_package(device, package); + status = acpi_bus_extract_wakeup_device_power_package(device->handle, + &device->wakeup); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); goto end; } - kfree(buffer.pointer); - device->wakeup.flags.valid = 1; device->wakeup.prepare_count = 0; acpi_bus_set_run_wake_flags(device); @@ -1351,6 +1371,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, struct acpi_bus_ops *ops = context; int type; unsigned long long sta; + struct acpi_device_wakeup wakeup; struct acpi_device *device; acpi_status status; int result; @@ -1360,8 +1381,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_OK; if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) + !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { + acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); return AE_CTRL_DEPTH; + } /* * We may already have an acpi_device from a previous enumeration. If diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 2737b9752205..e7df019d29d4 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -147,6 +147,39 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) clk_put(pclk); } +static int amba_get_enable_vcore(struct amba_device *pcdev) +{ + struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); + int ret; + + pcdev->vcore = vcore; + + if (IS_ERR(vcore)) { + /* It is OK not to supply a vcore regulator */ + if (PTR_ERR(vcore) == -ENODEV) + return 0; + return PTR_ERR(vcore); + } + + ret = regulator_enable(vcore); + if (ret) { + regulator_put(vcore); + pcdev->vcore = ERR_PTR(-ENODEV); + } + + return ret; +} + +static void amba_put_disable_vcore(struct amba_device *pcdev) +{ + struct regulator *vcore = pcdev->vcore; + + if (!IS_ERR(vcore)) { + regulator_disable(vcore); + regulator_put(vcore); + } +} + /* * These are the device model conversion veneers; they convert the * device model structures to our more specific structures. @@ -159,6 +192,10 @@ static int amba_probe(struct device *dev) int ret; do { + ret = amba_get_enable_vcore(pcdev); + if (ret) + break; + ret = amba_get_enable_pclk(pcdev); if (ret) break; @@ -168,6 +205,7 @@ static int amba_probe(struct device *dev) break; amba_put_disable_pclk(pcdev); + amba_put_disable_vcore(pcdev); } while (0); return ret; @@ -180,6 +218,7 @@ static int amba_remove(struct device *dev) int ret = drv->remove(pcdev); amba_put_disable_pclk(pcdev); + amba_put_disable_vcore(pcdev); return ret; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 11ec911016c6..36e2319264bd 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -128,16 +128,6 @@ config PDC_ADMA If unsure, say N. -config PATA_MPC52xx - tristate "Freescale MPC52xx SoC internal IDE" - depends on PPC_MPC52xx && PPC_BESTCOMM - select PPC_BESTCOMM_ATA - help - This option enables support for integrated IDE controller - of the Freescale MPC52xx SoC. - - If unsure, say N. - config PATA_OCTEON_CF tristate "OCTEON Boot Bus Compact Flash support" depends on CPU_CAVIUM_OCTEON @@ -366,7 +356,7 @@ config PATA_CS5535 config PATA_CS5536 tristate "CS5536 PATA support" - depends on PCI && X86 && !X86_64 + depends on PCI help This option enables support for the AMD CS5536 companion chip used with the Geode LX processor family. @@ -491,6 +481,16 @@ config PATA_MARVELL If unsure, say N. +config PATA_MPC52xx + tristate "Freescale MPC52xx SoC internal IDE" + depends on PPC_MPC52xx && PPC_BESTCOMM + select PPC_BESTCOMM_ATA + help + This option enables support for integrated IDE controller + of the Freescale MPC52xx SoC. + + If unsure, say N. + config PATA_NETCELL tristate "NETCELL Revolution RAID support" depends on PCI diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index c501af5b12b9..2b67c900a459 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o -obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o obj-$(CONFIG_SATA_SX4) += sata_sx4.o @@ -52,6 +51,7 @@ obj-$(CONFIG_PATA_IT821X) += pata_it821x.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_MACIO) += pata_macio.o obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o +obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 7f77c67d267c..f23d6d46b95b 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4807,9 +4807,6 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc) { struct ata_device *dev = qc->dev; - if (ata_tag_internal(qc->tag)) - return; - if (ata_is_nodata(qc->tf.protocol)) return; @@ -4858,14 +4855,23 @@ void ata_qc_complete(struct ata_queued_cmd *qc) if (unlikely(qc->err_mask)) qc->flags |= ATA_QCFLAG_FAILED; - if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { - /* always fill result TF for failed qc */ + /* + * Finish internal commands without any further processing + * and always with the result TF filled. + */ + if (unlikely(ata_tag_internal(qc->tag))) { fill_result_tf(qc); + __ata_qc_complete(qc); + return; + } - if (!ata_tag_internal(qc->tag)) - ata_qc_schedule_eh(qc); - else - __ata_qc_complete(qc); + /* + * Non-internal qc has failed. Fill the result TF and + * summon EH. + */ + if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) { + fill_result_tf(qc); + ata_qc_schedule_eh(qc); return; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 5e590504f3aa..17a637877d03 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3275,6 +3275,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL; struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; + enum ata_lpm_policy old_policy = link->lpm_policy; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; @@ -3338,6 +3339,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, goto fail; } + /* + * Low level driver acked the transition. Issue DIPM command + * with the new policy set. + */ + link->lpm_policy = policy; + if (ap && ap->slave_link) + ap->slave_link->lpm_policy = policy; + /* host config updated, enable DIPM if transitioning to MIN_POWER */ ata_for_each_dev(dev, link, ENABLED) { if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) { @@ -3353,12 +3362,14 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, } } - link->lpm_policy = policy; - if (ap && ap->slave_link) - ap->slave_link->lpm_policy = policy; return 0; fail: + /* restore the old policy */ + link->lpm_policy = old_policy; + if (ap && ap->slave_link) + ap->slave_link->lpm_policy = old_policy; + /* if no device or only one more chance is left, disable LPM */ if (!dev || ehc->tries[dev->devno] <= 2) { ata_link_printk(link, KERN_WARNING, diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index d05387d1e14b..484697fef386 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1532,11 +1532,10 @@ static unsigned int __ata_sff_port_intr(struct ata_port *ap, if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) return ata_sff_idle_irq(ap); break; - case HSM_ST: - case HSM_ST_LAST: - break; - default: + case HSM_ST_IDLE: return ata_sff_idle_irq(ap); + default: + break; } /* check main status, clearing INTRQ if needed */ diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index 21ee23f89e88..628c8fae5937 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -37,10 +37,22 @@ #include <linux/delay.h> #include <linux/libata.h> #include <scsi/scsi_host.h> + +#ifdef CONFIG_X86_32 #include <asm/msr.h> +static int use_msr; +module_param_named(msr, use_msr, int, 0644); +MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); +#else +#undef rdmsr /* avoid accidental MSR usage on, e.g. x86-64 */ +#undef wrmsr +#define rdmsr(x, y, z) do { } while (0) +#define wrmsr(x, y, z) do { } while (0) +#define use_msr 0 +#endif #define DRV_NAME "pata_cs5536" -#define DRV_VERSION "0.0.7" +#define DRV_VERSION "0.0.8" enum { CFG = 0, @@ -75,8 +87,6 @@ enum { IDE_ETC_NODMA = 0x03, }; -static int use_msr; - static const u32 msr_reg[4] = { MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC, }; @@ -88,7 +98,7 @@ static const u8 pci_reg[4] = { static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) { if (unlikely(use_msr)) { - u32 dummy; + u32 dummy __maybe_unused; rdmsr(msr_reg[reg], *val, dummy); return 0; @@ -294,8 +304,6 @@ MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, cs5536); MODULE_VERSION(DRV_VERSION); -module_param_named(msr, use_msr, int, 0644); -MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); module_init(cs5536_init); module_exit(cs5536_exit); diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 2b464b631f22..0b0625054a87 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -392,7 +392,10 @@ static int atmtcp_attach(struct atm_vcc *vcc,int itf) atm_dev_put(dev); return -EMEDIUMTYPE; } - if (PRIV(dev)->vcc) return -EBUSY; + if (PRIV(dev)->vcc) { + atm_dev_put(dev); + return -EBUSY; + } } else { int error; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f291587d753e..8e0f9256eb58 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2834,6 +2834,8 @@ static int cciss_revalidate(struct gendisk *disk) InquiryData_struct *inq_buff = NULL; for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) { + if (!h->drv[logvol]) + continue; if (memcmp(h->drv[logvol]->LunID, drv->LunID, sizeof(drv->LunID)) == 0) { FOUND = 1; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 89d8a7cc4054..24487d4fb202 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3627,17 +3627,19 @@ static void drbdd(struct drbd_conf *mdev) } shs = drbd_cmd_handler[cmd].pkt_size - sizeof(union p_header); - rv = drbd_recv(mdev, &header->h80.payload, shs); - if (unlikely(rv != shs)) { - dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); - goto err_out; - } - if (packet_size - shs > 0 && !drbd_cmd_handler[cmd].expect_payload) { dev_err(DEV, "No payload expected %s l:%d\n", cmdname(cmd), packet_size); goto err_out; } + if (shs) { + rv = drbd_recv(mdev, &header->h80.payload, shs); + if (unlikely(rv != shs)) { + dev_err(DEV, "short read while reading sub header: rv=%d\n", rv); + goto err_out; + } + } + rv = drbd_cmd_handler[cmd].function(mdev, cmd, packet_size - shs); if (unlikely(!rv)) { diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 181ea0364822..ab2bd09d54b4 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -339,7 +339,8 @@ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) } /* completion of master bio is outside of spinlock. - * If you need it irqsave, do it your self! */ + * If you need it irqsave, do it your self! + * Which means: don't use from bio endio callback. */ static inline int req_mod(struct drbd_request *req, enum drbd_req_event what) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 47d223c2409c..34f224b018b3 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -193,8 +193,10 @@ void drbd_endio_sec(struct bio *bio, int error) */ void drbd_endio_pri(struct bio *bio, int error) { + unsigned long flags; struct drbd_request *req = bio->bi_private; struct drbd_conf *mdev = req->mdev; + struct bio_and_error m; enum drbd_req_event what; int uptodate = bio_flagged(bio, BIO_UPTODATE); @@ -220,7 +222,13 @@ void drbd_endio_pri(struct bio *bio, int error) bio_put(req->private_bio); req->private_bio = ERR_PTR(error); - req_mod(req, what); + /* not req_mod(), we need irqsave here! */ + spin_lock_irqsave(&mdev->req_lock, flags); + __req_mod(req, what, &m); + spin_unlock_irqrestore(&mdev->req_lock, flags); + + if (m.bio) + complete_master_bio(mdev, &m); } int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 720148294e64..3c6cabcb7d84 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -311,8 +311,10 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { hu->proto->close(hu); - hci_unregister_dev(hdev); - hci_free_dev(hdev); + if (hdev) { + hci_unregister_dev(hdev); + hci_free_dev(hdev); + } } } } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 16a2847b7cdb..29ac6d499fa6 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1192,12 +1192,19 @@ static void i9xx_chipset_flush(void) writel(1, intel_private.i9xx_flush_page); } -static void i965_write_entry(dma_addr_t addr, unsigned int entry, +static void i965_write_entry(dma_addr_t addr, + unsigned int entry, unsigned int flags) { + u32 pte_flags; + + pte_flags = I810_PTE_VALID; + if (flags == AGP_USER_CACHED_MEMORY) + pte_flags |= I830_PTE_SYSTEM_CACHED; + /* Shift high bits down */ addr |= (addr >> 28) & 0xf0; - writel(addr | I810_PTE_VALID, intel_private.gtt + entry); + writel(addr | pte_flags, intel_private.gtt + entry); } static bool gen6_check_flags(unsigned int flags) diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c index 73dcb0ee41fd..d3d63be2cd37 100644 --- a/drivers/char/ramoops.c +++ b/drivers/char/ramoops.c @@ -29,7 +29,6 @@ #include <linux/ramoops.h> #define RAMOOPS_KERNMSG_HDR "====" -#define RAMOOPS_HEADER_SIZE (5 + sizeof(struct timeval)) #define RECORD_SIZE 4096 @@ -65,8 +64,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, struct ramoops_context, dump); unsigned long s1_start, s2_start; unsigned long l1_cpy, l2_cpy; - int res; - char *buf; + int res, hdr_size; + char *buf, *buf_orig; struct timeval timestamp; /* Only dump oopses if dump_oops is set */ @@ -74,6 +73,8 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, return; buf = (char *)(cxt->virt_addr + (cxt->count * RECORD_SIZE)); + buf_orig = buf; + memset(buf, '\0', RECORD_SIZE); res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR); buf += res; @@ -81,8 +82,9 @@ static void ramoops_do_dump(struct kmsg_dumper *dumper, res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec); buf += res; - l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE)); - l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - RAMOOPS_HEADER_SIZE) - l2_cpy); + hdr_size = buf - buf_orig; + l2_cpy = min(l2, (unsigned long)(RECORD_SIZE - hdr_size)); + l1_cpy = min(l1, (unsigned long)(RECORD_SIZE - hdr_size) - l2_cpy); s2_start = l2 - l2_cpy; s1_start = l1 - l1_cpy; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig new file mode 100644 index 000000000000..4168c8896e16 --- /dev/null +++ b/drivers/clk/Kconfig @@ -0,0 +1,4 @@ + +config CLKDEV_LOOKUP + bool + select HAVE_CLK diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile new file mode 100644 index 000000000000..07613fa172c9 --- /dev/null +++ b/drivers/clk/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c new file mode 100644 index 000000000000..0fc0a79852de --- /dev/null +++ b/drivers/clk/clkdev.c @@ -0,0 +1,176 @@ +/* + * drivers/clk/clkdev.c + * + * Copyright (C) 2008 Russell King. + * + * 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. + * + * Helper for the clk API to assist looking up a struct clk. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/string.h> +#include <linux/mutex.h> +#include <linux/clk.h> +#include <linux/clkdev.h> + +static LIST_HEAD(clocks); +static DEFINE_MUTEX(clocks_mutex); + +/* + * Find the correct struct clk for the device and connection ID. + * We do slightly fuzzy matching here: + * An entry with a NULL ID is assumed to be a wildcard. + * If an entry has a device ID, it must match + * If an entry has a connection ID, it must match + * Then we take the most specific entry - with the following + * order of precedence: dev+con > dev only > con only. + */ +static struct clk *clk_find(const char *dev_id, const char *con_id) +{ + struct clk_lookup *p; + struct clk *clk = NULL; + int match, best = 0; + + list_for_each_entry(p, &clocks, node) { + match = 0; + if (p->dev_id) { + if (!dev_id || strcmp(p->dev_id, dev_id)) + continue; + match += 2; + } + if (p->con_id) { + if (!con_id || strcmp(p->con_id, con_id)) + continue; + match += 1; + } + + if (match > best) { + clk = p->clk; + if (match != 3) + best = match; + else + break; + } + } + return clk; +} + +struct clk *clk_get_sys(const char *dev_id, const char *con_id) +{ + struct clk *clk; + + mutex_lock(&clocks_mutex); + clk = clk_find(dev_id, con_id); + if (clk && !__clk_get(clk)) + clk = NULL; + mutex_unlock(&clocks_mutex); + + return clk ? clk : ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get_sys); + +struct clk *clk_get(struct device *dev, const char *con_id) +{ + const char *dev_id = dev ? dev_name(dev) : NULL; + + return clk_get_sys(dev_id, con_id); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ + __clk_put(clk); +} +EXPORT_SYMBOL(clk_put); + +void clkdev_add(struct clk_lookup *cl) +{ + mutex_lock(&clocks_mutex); + list_add_tail(&cl->node, &clocks); + mutex_unlock(&clocks_mutex); +} +EXPORT_SYMBOL(clkdev_add); + +void __init clkdev_add_table(struct clk_lookup *cl, size_t num) +{ + mutex_lock(&clocks_mutex); + while (num--) { + list_add_tail(&cl->node, &clocks); + cl++; + } + mutex_unlock(&clocks_mutex); +} + +#define MAX_DEV_ID 20 +#define MAX_CON_ID 16 + +struct clk_lookup_alloc { + struct clk_lookup cl; + char dev_id[MAX_DEV_ID]; + char con_id[MAX_CON_ID]; +}; + +struct clk_lookup * __init_refok +clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) +{ + struct clk_lookup_alloc *cla; + + cla = __clkdev_alloc(sizeof(*cla)); + if (!cla) + return NULL; + + cla->cl.clk = clk; + if (con_id) { + strlcpy(cla->con_id, con_id, sizeof(cla->con_id)); + cla->cl.con_id = cla->con_id; + } + + if (dev_fmt) { + va_list ap; + + va_start(ap, dev_fmt); + vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); + cla->cl.dev_id = cla->dev_id; + va_end(ap); + } + + return &cla->cl; +} +EXPORT_SYMBOL(clkdev_alloc); + +int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, + struct device *dev) +{ + struct clk *r = clk_get(dev, id); + struct clk_lookup *l; + + if (IS_ERR(r)) + return PTR_ERR(r); + + l = clkdev_alloc(r, alias, alias_dev_name); + clk_put(r); + if (!l) + return -ENODEV; + clkdev_add(l); + return 0; +} +EXPORT_SYMBOL(clk_add_alias); + +/* + * clkdev_drop - remove a clock dynamically allocated + */ +void clkdev_drop(struct clk_lookup *cl) +{ + mutex_lock(&clocks_mutex); + list_del(&cl->node); + mutex_unlock(&clocks_mutex); + kfree(cl); +} +EXPORT_SYMBOL(clkdev_drop); diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index d68d3aa1814b..f975d24890fa 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -283,16 +283,21 @@ static void sh_cmt_clock_event_program_verify(struct sh_cmt_priv *p, } while (delay); } -static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) +static void __sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) { - unsigned long flags; - if (delta > p->max_match_value) dev_warn(&p->pdev->dev, "delta out of range\n"); - spin_lock_irqsave(&p->lock, flags); p->next_match_value = delta; sh_cmt_clock_event_program_verify(p, 0); +} + +static void sh_cmt_set_next(struct sh_cmt_priv *p, unsigned long delta) +{ + unsigned long flags; + + spin_lock_irqsave(&p->lock, flags); + __sh_cmt_set_next(p, delta); spin_unlock_irqrestore(&p->lock, flags); } @@ -359,7 +364,7 @@ static int sh_cmt_start(struct sh_cmt_priv *p, unsigned long flag) /* setup timeout if no clockevent */ if ((flag == FLAG_CLOCKSOURCE) && (!(p->flags & FLAG_CLOCKEVENT))) - sh_cmt_set_next(p, p->max_match_value); + __sh_cmt_set_next(p, p->max_match_value); out: spin_unlock_irqrestore(&p->lock, flags); @@ -381,7 +386,7 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag) /* adjust the timeout to maximum if only clocksource left */ if ((flag == FLAG_CLOCKEVENT) && (p->flags & FLAG_CLOCKSOURCE)) - sh_cmt_set_next(p, p->max_match_value); + __sh_cmt_set_next(p, p->max_match_value); spin_unlock_irqrestore(&p->lock, flags); } diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 411d5bf50fc4..a25f5f61e0e0 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -449,7 +449,7 @@ mv_xor_slot_cleanup(struct mv_xor_chan *mv_chan) static void mv_xor_tasklet(unsigned long data) { struct mv_xor_chan *chan = (struct mv_xor_chan *) data; - __mv_xor_slot_cleanup(chan); + mv_xor_slot_cleanup(chan); } static struct mv_xor_desc_slot * diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 599f6c9e0fbf..d3e55a0ae92b 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -56,15 +56,26 @@ static struct cs5535_gpio_chip { * registers, see include/linux/cs5535.h. */ -static void errata_outl(u32 val, unsigned long addr) +static void errata_outl(struct cs5535_gpio_chip *chip, u32 val, + unsigned int reg) { + unsigned long addr = chip->base + 0x80 + reg; + /* * According to the CS5536 errata (#36), after suspend * a write to the high bank GPIO register will clear all * non-selected bits; the recommended workaround is a * read-modify-write operation. + * + * Don't apply this errata to the edge status GPIOs, as writing + * to their lower bits will clear them. */ - val |= inl(addr); + if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) { + if (val & 0xffff) + val |= (inl(addr) & 0xffff); /* ignore the high bits */ + else + val |= (inl(addr) ^ (val >> 16)); + } outl(val, addr); } @@ -76,7 +87,7 @@ static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << offset, chip->base + reg); else /* high bank register */ - errata_outl(1 << (offset - 16), chip->base + 0x80 + reg); + errata_outl(chip, 1 << (offset - 16), reg); } void cs5535_gpio_set(unsigned offset, unsigned int reg) @@ -98,7 +109,7 @@ static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << (offset + 16), chip->base + reg); else /* high bank register */ - errata_outl(1 << offset, chip->base + 0x80 + reg); + errata_outl(chip, 1 << offset, reg); } void cs5535_gpio_clear(unsigned offset, unsigned int reg) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 21da9c19a0cb..649550e2cae9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1281,6 +1281,9 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label) err = gpio_direction_output(gpio, (flags & GPIOF_INIT_HIGH) ? 1 : 0); + if (err) + gpio_free(gpio); + return err; } EXPORT_SYMBOL_GPL(gpio_request_one); diff --git a/drivers/gpio/rdc321x-gpio.c b/drivers/gpio/rdc321x-gpio.c index 2762698e0204..897e0577e65e 100644 --- a/drivers/gpio/rdc321x-gpio.c +++ b/drivers/gpio/rdc321x-gpio.c @@ -135,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; - pdata = pdev->dev.platform_data; + pdata = platform_get_drvdata(pdev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index bede10a03407..2d4e17a004db 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -241,7 +241,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc && !drm_helper_encoder_in_use(encoder)) { + if (!drm_helper_encoder_in_use(encoder)) { drm_encoder_disable(encoder); /* disconnector encoder from any connector */ encoder->crtc = NULL; @@ -874,7 +874,10 @@ static void output_poll_execute(struct work_struct *work) continue; connector->status = connector->funcs->detect(connector, false); - DRM_DEBUG_KMS("connector status updated to %d\n", connector->status); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + connector->base.id, + drm_get_connector_name(connector), + old_status, connector->status); if (old_status != connector->status) changed = true; } diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c index af70337567ce..d3e8c540f778 100644 --- a/drivers/gpu/drm/i915/dvo_ch7017.c +++ b/drivers/gpu/drm/i915/dvo_ch7017.c @@ -242,7 +242,7 @@ fail: static enum drm_connector_status ch7017_detect(struct intel_dvo_device *dvo) { - return connector_status_unknown; + return connector_status_connected; } static enum drm_mode_status ch7017_mode_valid(struct intel_dvo_device *dvo, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e6800819bca8..cb900dc83d95 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -34,6 +34,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include "i915_trace.h" +#include "../../../platform/x86/intel_ips.h" #include <linux/pci.h> #include <linux/vgaarb.h> #include <linux/acpi.h> @@ -1871,6 +1872,26 @@ out_unlock: EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable); /** + * Tells the intel_ips driver that the i915 driver is now loaded, if + * IPS got loaded first. + * + * This awkward dance is so that neither module has to depend on the + * other in order for IPS to do the appropriate communication of + * GPU turbo limits to i915. + */ +static void +ips_ping_for_i915_load(void) +{ + void (*link)(void); + + link = symbol_get(ips_link_to_i915_driver); + if (link) { + link(); + symbol_put(ips_link_to_i915_driver); + } +} + +/** * i915_driver_load - setup chip and create an initial config * @dev: DRM device * @flags: startup flags @@ -2075,6 +2096,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->mchdev_lock = &mchdev_lock; spin_unlock(&mchdev_lock); + ips_ping_for_i915_load(); + return 0; out_workqueue_free: diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 878fc766a12c..cb8f43429279 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2471,6 +2471,9 @@ # define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18) # define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1) +#define PCH_3DCGDIS1 0x46024 +# define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11) + #define FDI_PLL_FREQ_CTL 0x46030 #define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) #define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 @@ -2588,6 +2591,13 @@ #define ILK_DISPLAY_CHICKEN2 0x42004 #define ILK_DPARB_GATE (1<<22) #define ILK_VSDPFD_FULL (1<<21) +#define ILK_DISPLAY_CHICKEN_FUSES 0x42014 +#define ILK_INTERNAL_GRAPHICS_DISABLE (1<<31) +#define ILK_INTERNAL_DISPLAY_DISABLE (1<<30) +#define ILK_DISPLAY_DEBUG_DISABLE (1<<29) +#define ILK_HDCP_DISABLE (1<<25) +#define ILK_eDP_A_DISABLE (1<<24) +#define ILK_DESKTOP (1<<23) #define ILK_DSPCLK_GATE 0x42020 #define ILK_DPARB_CLK_GATE (1<<5) /* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d9b7092439ef..fca523288aca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5379,6 +5379,23 @@ static int intel_encoder_clones(struct drm_device *dev, int type_mask) return index_mask; } +static bool has_edp_a(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!IS_MOBILE(dev)) + return false; + + if ((I915_READ(DP_A) & DP_DETECTED) == 0) + return false; + + if (IS_GEN5(dev) && + (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE)) + return false; + + return true; +} + static void intel_setup_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5396,7 +5413,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { dpd_is_edp = intel_dpd_is_edp(dev); - if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED)) + if (has_edp_a(dev)) intel_dp_init(dev, DP_A); if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) @@ -5825,6 +5842,8 @@ void intel_init_clock_gating(struct drm_device *dev) I915_WRITE(PCH_3DCGDIS0, MARIUNIT_CLOCK_GATE_DISABLE | SVSMUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(PCH_3DCGDIS1, + VFMUNIT_CLOCK_GATE_DISABLE); } I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index df648cb4c296..864417cffe9a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -479,6 +479,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, uint16_t address = algo_data->address; uint8_t msg[5]; uint8_t reply[2]; + unsigned retry; int msg_bytes; int reply_bytes; int ret; @@ -513,14 +514,33 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, break; } - for (;;) { - ret = intel_dp_aux_ch(intel_dp, - msg, msg_bytes, - reply, reply_bytes); + for (retry = 0; retry < 5; retry++) { + ret = intel_dp_aux_ch(intel_dp, + msg, msg_bytes, + reply, reply_bytes); if (ret < 0) { DRM_DEBUG_KMS("aux_ch failed %d\n", ret); return ret; } + + switch (reply[0] & AUX_NATIVE_REPLY_MASK) { + case AUX_NATIVE_REPLY_ACK: + /* I2C-over-AUX Reply field is only valid + * when paired with AUX ACK. + */ + break; + case AUX_NATIVE_REPLY_NACK: + DRM_DEBUG_KMS("aux_ch native nack\n"); + return -EREMOTEIO; + case AUX_NATIVE_REPLY_DEFER: + udelay(100); + continue; + default: + DRM_ERROR("aux_ch invalid native reply 0x%02x\n", + reply[0]); + return -EREMOTEIO; + } + switch (reply[0] & AUX_I2C_REPLY_MASK) { case AUX_I2C_REPLY_ACK: if (mode == MODE_I2C_READ) { @@ -528,17 +548,20 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } return reply_bytes - 1; case AUX_I2C_REPLY_NACK: - DRM_DEBUG_KMS("aux_ch nack\n"); + DRM_DEBUG_KMS("aux_i2c nack\n"); return -EREMOTEIO; case AUX_I2C_REPLY_DEFER: - DRM_DEBUG_KMS("aux_ch defer\n"); + DRM_DEBUG_KMS("aux_i2c defer\n"); udelay(100); break; default: - DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]); + DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]); return -EREMOTEIO; } } + + DRM_ERROR("too many retries, giving up\n"); + return -EREMOTEIO; } static int diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 89a65be8a3f3..31cd7e33e820 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -696,20 +696,17 @@ int intel_wait_ring_buffer(struct drm_device *dev, drm_i915_private_t *dev_priv = dev->dev_private; u32 head; - head = intel_read_status_page(ring, 4); - if (head) { - ring->head = head & HEAD_ADDR; - ring->space = ring->head - (ring->tail + 8); - if (ring->space < 0) - ring->space += ring->size; - if (ring->space >= n) - return 0; - } - trace_i915_ring_wait_begin (dev); end = jiffies + 3 * HZ; do { - ring->head = I915_READ_HEAD(ring) & HEAD_ADDR; + /* If the reported head position has wrapped or hasn't advanced, + * fallback to the slow and accurate path. + */ + head = intel_read_status_page(ring, 4); + if (head < ring->actual_head) + head = I915_READ_HEAD(ring); + ring->actual_head = head; + ring->head = head & HEAD_ADDR; ring->space = ring->head - (ring->tail + 8); if (ring->space < 0) ring->space += ring->size; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 3126c2681983..d2cd0f1efeed 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -30,8 +30,9 @@ struct intel_ring_buffer { struct drm_device *dev; struct drm_gem_object *gem_object; - unsigned int head; - unsigned int tail; + u32 actual_head; + u32 head; + u32 tail; int space; struct intel_hw_status_page status_page; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index d97e6cb52d34..6bc42fa2a6ec 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1908,9 +1908,12 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, speed = mapping->i2c_speed; } - sdvo->i2c = &dev_priv->gmbus[pin].adapter; - intel_gmbus_set_speed(sdvo->i2c, speed); - intel_gmbus_force_bit(sdvo->i2c, true); + if (pin < GMBUS_NUM_PORTS) { + sdvo->i2c = &dev_priv->gmbus[pin].adapter; + intel_gmbus_set_speed(sdvo->i2c, speed); + intel_gmbus_force_bit(sdvo->i2c, true); + } else + sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter; } static bool @@ -2037,13 +2040,14 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) SDVO_COLORIMETRY_RGB256); connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); intel_sdvo->is_hdmi = true; } intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) | (1 << INTEL_ANALOG_CLONE_BIT)); intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); + if (intel_sdvo->is_hdmi) + intel_sdvo_add_hdmi_properties(intel_sdvo_connector); return true; } diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index df2b6f2b35f8..9fbabaa6ee44 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -253,7 +253,8 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode) case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: drm_vblank_pre_modeset(dev, radeon_crtc->crtc_id); - atombios_blank_crtc(crtc, ATOM_ENABLE); + if (radeon_crtc->enabled) + atombios_blank_crtc(crtc, ATOM_ENABLE); if (ASIC_IS_DCE3(rdev)) atombios_enable_crtc_memreq(crtc, ATOM_DISABLE); atombios_enable_crtc(crtc, ATOM_DISABLE); @@ -530,7 +531,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, dp_clock = dig_connector->dp_clock; } } - +#if 0 /* doesn't work properly on some laptops */ /* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { @@ -540,7 +541,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, } } } - +#endif if (ASIC_IS_AVIVO(rdev)) { /* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */ if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 4dc5b4714c5a..7b337c361a12 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -748,6 +748,8 @@ void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev) unsigned i; u32 tmp; + WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); + WREG32(VM_CONTEXT0_REQUEST_RESPONSE, REQUEST_TYPE(1)); for (i = 0; i < rdev->usec_timeout; i++) { /* read MC_STATUS */ @@ -1922,7 +1924,6 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev) static int evergreen_gpu_soft_reset(struct radeon_device *rdev) { struct evergreen_mc_save save; - u32 srbm_reset = 0; u32 grbm_reset = 0; dev_info(rdev->dev, "GPU softreset \n"); @@ -1961,16 +1962,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) udelay(50); WREG32(GRBM_SOFT_RESET, 0); (void)RREG32(GRBM_SOFT_RESET); - - /* reset all the system blocks */ - srbm_reset = SRBM_SOFT_RESET_ALL_MASK; - - dev_info(rdev->dev, " SRBM_SOFT_RESET=0x%08X\n", srbm_reset); - WREG32(SRBM_SOFT_RESET, srbm_reset); - (void)RREG32(SRBM_SOFT_RESET); - udelay(50); - WREG32(SRBM_SOFT_RESET, 0); - (void)RREG32(SRBM_SOFT_RESET); /* Wait a little for things to settle down */ udelay(50); dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n", @@ -1981,10 +1972,6 @@ static int evergreen_gpu_soft_reset(struct radeon_device *rdev) RREG32(GRBM_STATUS_SE1)); dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n", RREG32(SRBM_STATUS)); - /* After reset we need to reinit the asic as GPU often endup in an - * incoherent state. - */ - atom_asic_init(rdev->mode_info.atom_context); evergreen_mc_resume(rdev, &save); return 0; } @@ -2596,6 +2583,11 @@ int evergreen_resume(struct radeon_device *rdev) { int r; + /* reset the asic, the gfx blocks are often in a bad state + * after the driver is unloaded or after a resume + */ + if (radeon_asic_reset(rdev)) + dev_warn(rdev->dev, "GPU reset failed !\n"); /* Do not reset GPU before posting, on rv770 hw unlike on r500 hw, * posting will perform necessary task to bring back GPU into good * shape. @@ -2712,6 +2704,11 @@ int evergreen_init(struct radeon_device *rdev) r = radeon_atombios_init(rdev); if (r) return r; + /* reset the asic, the gfx blocks are often in a bad state + * after the driver is unloaded or after a resume + */ + if (radeon_asic_reset(rdev)) + dev_warn(rdev->dev, "GPU reset failed !\n"); /* Post card if necessary */ if (!evergreen_card_posted(rdev)) { if (!rdev->bios) { diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 113c70cc8b39..a73b53c44359 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -174,6 +174,7 @@ #define HDP_NONSURFACE_BASE 0x2C04 #define HDP_NONSURFACE_INFO 0x2C08 #define HDP_NONSURFACE_SIZE 0x2C0C +#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480 #define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 #define HDP_TILING_CONFIG 0x2F3C diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4d7a2e1bdb90..9c92db7c896b 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1342,13 +1342,19 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) u32 srbm_status; u32 grbm_status; u32 grbm_status2; + struct r100_gpu_lockup *lockup; int r; + if (rdev->family >= CHIP_RV770) + lockup = &rdev->config.rv770.lockup; + else + lockup = &rdev->config.r600.lockup; + srbm_status = RREG32(R_000E50_SRBM_STATUS); grbm_status = RREG32(R_008010_GRBM_STATUS); grbm_status2 = RREG32(R_008014_GRBM_STATUS2); if (!G_008010_GUI_ACTIVE(grbm_status)) { - r100_gpu_lockup_update(&rdev->config.r300.lockup, &rdev->cp); + r100_gpu_lockup_update(lockup, &rdev->cp); return false; } /* force CP activities */ @@ -1360,7 +1366,7 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev) radeon_ring_unlock_commit(rdev); } rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); - return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, &rdev->cp); + return r100_gpu_cp_is_lockup(rdev, lockup, &rdev->cp); } int r600_asic_reset(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0f90fc3482ce..7831e0890210 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -315,11 +315,10 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) { /* the initial DDX does bad things with the CB size occasionally */ /* it rounds up height too far for slice tile max but the BO is smaller */ - tmp = (height - 7) * 8 * bpe; - if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { - dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); - return -EINVAL; - } + /* r600c,g also seem to flush at bad times in some apps resulting in + * bogus values here. So for linear just allow anything to avoid breaking + * broken userspace. + */ } else { dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i])); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index e12e79326cb1..501966a13f48 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -910,11 +910,6 @@ int radeon_resume_kms(struct drm_device *dev) radeon_pm_resume(rdev); radeon_restore_bios_scratch_regs(rdev); - /* turn on display hw */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - radeon_fbdev_set_suspend(rdev, 0); release_console_sem(); @@ -922,6 +917,10 @@ int radeon_resume_kms(struct drm_device *dev) radeon_hpd_init(rdev); /* blat the mode back in */ drm_helper_resume_force_mode(dev); + /* turn on display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 88e4ea925900..60e689f2d048 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -232,9 +232,28 @@ static struct drm_driver driver_old = { static struct drm_driver kms_driver; +static void radeon_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + bool primary = false; + + ap = alloc_apertures(1); + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; +#endif + remove_conflicting_framebuffers(ap, "radeondrmfb", primary); + kfree(ap); +} + static int __devinit radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + /* Get rid of things like offb */ + radeon_kick_out_firmware_fb(pdev); + return drm_get_pci_dev(pdev, ent, &kms_driver); } diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index efa211898fe6..6abea32be5e8 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -245,7 +245,7 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev, goto out_unref; } info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base; - info->apertures->ranges[0].size = rdev->mc.real_vram_size; + info->apertures->ranges[0].size = rdev->mc.aper_size; info->fix.mmio_start = 0; info->fix.mmio_len = 0; diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index 05248f2d7581..92b42db43bcf 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -234,7 +234,6 @@ static int s3c_hwmon_create_attr(struct device *dev, attr->index = channel; attr->dev_attr.attr.name = attrs->in_name; attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; attr->dev_attr.show = s3c_hwmon_ch_show; ret = device_create_file(dev, &attr->dev_attr); @@ -252,7 +251,6 @@ static int s3c_hwmon_create_attr(struct device *dev, attr->index = channel; attr->dev_attr.attr.name = attrs->label_name; attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; attr->dev_attr.show = s3c_hwmon_label_show; ret = device_create_file(dev, &attr->dev_attr); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e3f7fc6f9565..68f09a868434 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -534,76 +534,73 @@ static int handle_eviocgbit(struct input_dev *dev, } #undef OLD_KEY_MAX -static int evdev_handle_get_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; int error; - memset(&ke, 0, sizeof(ke)); - - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + /* legacy case */ + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - ke.len = sizeof(unsigned int); - ke.flags = 0; + if (put_user(ke.keycode, ip + 1)) + return -EFAULT; - error = input_get_keycode(dev, &ke); - if (error) - return error; + return 0; +} - if (put_user(ke.keycode, ip + 1)) - return -EFAULT; +static int evdev_handle_get_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; + int error; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; + error = input_get_keycode(dev, &ke); + if (error) + return error; - error = input_get_keycode(dev, &ke); - if (error) - return error; + if (copy_to_user(p, &ke, sizeof(ke))) + return -EFAULT; - if (copy_to_user(p, &ke, size)) - return -EFAULT; - } return 0; } -static int evdev_handle_set_keycode(struct input_dev *dev, - void __user *p, size_t size) +static int evdev_handle_set_keycode(struct input_dev *dev, void __user *p) { - struct input_keymap_entry ke; - - memset(&ke, 0, sizeof(ke)); + struct input_keymap_entry ke = { + .len = sizeof(unsigned int), + .flags = 0, + }; + int __user *ip = (int __user *)p; - if (size == sizeof(unsigned int[2])) { - /* legacy case */ - int __user *ip = (int __user *)p; + if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) + return -EFAULT; - if (copy_from_user(ke.scancode, p, sizeof(unsigned int))) - return -EFAULT; + if (get_user(ke.keycode, ip + 1)) + return -EFAULT; - if (get_user(ke.keycode, ip + 1)) - return -EFAULT; + return input_set_keycode(dev, &ke); +} - ke.len = sizeof(unsigned int); - ke.flags = 0; +static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) +{ + struct input_keymap_entry ke; - } else { - size = min(size, sizeof(ke)); + if (copy_from_user(&ke, p, sizeof(ke))) + return -EFAULT; - if (copy_from_user(&ke, p, size)) - return -EFAULT; - - if (ke.len > sizeof(ke.scancode)) - return -EINVAL; - } + if (ke.len > sizeof(ke.scancode)) + return -EINVAL; return input_set_keycode(dev, &ke); } @@ -669,6 +666,18 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return evdev_grab(evdev, client); else return evdev_ungrab(evdev, client); + + case EVIOCGKEYCODE: + return evdev_handle_get_keycode(dev, p); + + case EVIOCSKEYCODE: + return evdev_handle_set_keycode(dev, p); + + case EVIOCGKEYCODE_V2: + return evdev_handle_get_keycode_v2(dev, p); + + case EVIOCSKEYCODE_V2: + return evdev_handle_set_keycode_v2(dev, p); } size = _IOC_SIZE(cmd); @@ -708,12 +717,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return -EFAULT; return error; - - case EVIOC_MASK_SIZE(EVIOCGKEYCODE): - return evdev_handle_get_keycode(dev, p, size); - - case EVIOC_MASK_SIZE(EVIOCSKEYCODE): - return evdev_handle_set_keycode(dev, p, size); } /* Multi-number variable-length handlers */ diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 4852b440960a..435b0af401e4 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1436,6 +1436,8 @@ static struct wacom_features wacom_features_0xD2 = { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; +static const struct wacom_features wacom_features_0xD4 = + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xD8 = { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xDA = @@ -1510,6 +1512,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xD1) }, { USB_DEVICE_WACOM(0xD2) }, { USB_DEVICE_WACOM(0xD3) }, + { USB_DEVICE_WACOM(0xD4) }, { USB_DEVICE_WACOM(0xD8) }, { USB_DEVICE_WACOM(0xDA) }, { USB_DEVICE_WACOM(0xDB) }, diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index bcc174e4f3b1..658e75f18d05 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -1900,6 +1900,7 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, if (b3skb == NULL) { dev_err(cs->dev, "%s: out of memory\n", __func__); send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); + kfree(b3cmsg); return; } capi_cmsg2message(b3cmsg, diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 211e21f34bd5..d5a4ade88991 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -267,7 +267,7 @@ void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_off) { if (led_cdev->blink_set && - led_cdev->blink_set(led_cdev, delay_on, delay_off)) + !led_cdev->blink_set(led_cdev, delay_on, delay_off)) return; /* blink with 1 Hz as default if nothing specified */ diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 90267f8d64ee..4d705cea0f8c 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -517,9 +517,8 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, */ if (q->merge_bvec_fn && !ti->type->merge) - limits->max_sectors = - min_not_zero(limits->max_sectors, - (unsigned int) (PAGE_SIZE >> 9)); + blk_limits_max_hw_sectors(limits, + (unsigned int) (PAGE_SIZE >> 9)); return 0; } EXPORT_SYMBOL_GPL(dm_set_device_limits); @@ -1131,11 +1130,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, */ q->limits = *limits; - if (limits->no_cluster) - queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); - else - queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); - if (!dm_table_supports_discards(t)) queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); else diff --git a/drivers/md/md.c b/drivers/md/md.c index e71c5fa527f5..175c424f201f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4295,9 +4295,6 @@ static int md_alloc(dev_t dev, char *name) goto abort; mddev->queue->queuedata = mddev; - /* Can be unlocked because the queue is new: no concurrency */ - queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue); - blk_queue_make_request(mddev->queue, md_make_request); disk = alloc_disk(1 << shift); diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c index 1b7adabbcee9..6da955dfef48 100644 --- a/drivers/media/IR/keymaps/rc-rc6-mce.c +++ b/drivers/media/IR/keymaps/rc-rc6-mce.c @@ -26,8 +26,8 @@ static struct ir_scancode rc6_mce[] = { { 0x800f040a, KEY_DELETE }, { 0x800f040b, KEY_ENTER }, - { 0x800f040c, KEY_POWER }, - { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ + { 0x800f040c, KEY_POWER }, /* PC Power */ + { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ { 0x800f040e, KEY_MUTE }, { 0x800f040f, KEY_INFO }, @@ -56,31 +56,32 @@ static struct ir_scancode rc6_mce[] = { { 0x800f0422, KEY_OK }, { 0x800f0423, KEY_EXIT }, { 0x800f0424, KEY_DVD }, - { 0x800f0425, KEY_TUNER }, /* LiveTV */ - { 0x800f0426, KEY_EPG }, /* Guide */ - { 0x800f0427, KEY_ZOOM }, /* Aspect */ + { 0x800f0425, KEY_TUNER }, /* LiveTV */ + { 0x800f0426, KEY_EPG }, /* Guide */ + { 0x800f0427, KEY_ZOOM }, /* Aspect */ { 0x800f043a, KEY_BRIGHTNESSUP }, { 0x800f0446, KEY_TV }, - { 0x800f0447, KEY_AUDIO }, /* My Music */ - { 0x800f0448, KEY_PVR }, /* RecordedTV */ + { 0x800f0447, KEY_AUDIO }, /* My Music */ + { 0x800f0448, KEY_PVR }, /* RecordedTV */ { 0x800f0449, KEY_CAMERA }, { 0x800f044a, KEY_VIDEO }, { 0x800f044c, KEY_LANGUAGE }, { 0x800f044d, KEY_TITLE }, - { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ + { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ { 0x800f0450, KEY_RADIO }, - { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ + { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ { 0x800f045b, KEY_RED }, { 0x800f045c, KEY_GREEN }, { 0x800f045d, KEY_YELLOW }, { 0x800f045e, KEY_BLUE }, + { 0x800f0465, KEY_POWER2 }, /* TV Power */ { 0x800f046e, KEY_PLAYPAUSE }, - { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */ + { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */ { 0x800f0480, KEY_BRIGHTNESSDOWN }, { 0x800f0481, KEY_PLAYPAUSE }, diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c index 8418b14ee4d2..756656e17bdd 100644 --- a/drivers/media/IR/lirc_dev.c +++ b/drivers/media/IR/lirc_dev.c @@ -522,10 +522,8 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); - if (!ir->attached) { - mutex_unlock(&ir->irctl_lock); + if (!ir->attached) return POLLERR; - } poll_wait(file, &ir->buf->wait_poll, wait); @@ -649,18 +647,18 @@ ssize_t lirc_dev_fop_read(struct file *file, if (!buf) return -ENOMEM; - if (mutex_lock_interruptible(&ir->irctl_lock)) - return -ERESTARTSYS; + if (mutex_lock_interruptible(&ir->irctl_lock)) { + ret = -ERESTARTSYS; + goto out_unlocked; + } if (!ir->attached) { - mutex_unlock(&ir->irctl_lock); - return -ENODEV; + ret = -ENODEV; + goto out_locked; } if (length % ir->chunk_size) { - dev_dbg(ir->d.dev, LOGHEAD "read result = -EINVAL\n", - ir->d.name, ir->d.minor); - mutex_unlock(&ir->irctl_lock); - return -EINVAL; + ret = -EINVAL; + goto out_locked; } /* @@ -711,18 +709,23 @@ ssize_t lirc_dev_fop_read(struct file *file, lirc_buffer_read(ir->buf, buf); ret = copy_to_user((void *)buffer+written, buf, ir->buf->chunk_size); - written += ir->buf->chunk_size; + if (!ret) + written += ir->buf->chunk_size; + else + ret = -EFAULT; } } remove_wait_queue(&ir->buf->wait_poll, &wait); set_current_state(TASK_RUNNING); + +out_locked: mutex_unlock(&ir->irctl_lock); out_unlocked: kfree(buf); dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", - ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); + ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret); return ret ? ret : written; } diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c index 9dce684fd231..392ca24132da 100644 --- a/drivers/media/IR/mceusb.c +++ b/drivers/media/IR/mceusb.c @@ -35,10 +35,10 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/usb.h> #include <linux/input.h> +#include <linux/usb.h> +#include <linux/usb/input.h> #include <media/ir-core.h> -#include <media/ir-common.h> #define DRIVER_VERSION "1.91" #define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>" @@ -49,6 +49,7 @@ #define USB_BUFLEN 32 /* USB reception buffer length */ #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ +#define MS_TO_NS(msec) ((msec) * 1000) /* MCE constants */ #define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ @@ -74,6 +75,7 @@ #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ /* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */ +#define MCE_CMD_SIG_END 0x01 /* End of signal */ #define MCE_CMD_PING 0x03 /* Ping device */ #define MCE_CMD_UNKNOWN 0x04 /* Unknown */ #define MCE_CMD_UNKNOWN2 0x05 /* Unknown */ @@ -91,6 +93,7 @@ #define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */ #define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */ #define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */ +#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */ #define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */ #define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */ #define MCE_CMD_UNKNOWN7 0x18 /* Unknown */ @@ -146,14 +149,16 @@ enum mceusb_model_type { MCE_GEN3, MCE_GEN2_TX_INV, POLARIS_EVK, + CX_HYBRID_TV, }; struct mceusb_model { u32 mce_gen1:1; u32 mce_gen2:1; u32 mce_gen3:1; - u32 tx_mask_inverted:1; + u32 tx_mask_normal:1; u32 is_polaris:1; + u32 no_tx:1; const char *rc_map; /* Allow specify a per-board map */ const char *name; /* per-board name */ @@ -162,18 +167,18 @@ struct mceusb_model { static const struct mceusb_model mceusb_model[] = { [MCE_GEN1] = { .mce_gen1 = 1, - .tx_mask_inverted = 1, + .tx_mask_normal = 1, }, [MCE_GEN2] = { .mce_gen2 = 1, }, [MCE_GEN2_TX_INV] = { .mce_gen2 = 1, - .tx_mask_inverted = 1, + .tx_mask_normal = 1, }, [MCE_GEN3] = { .mce_gen3 = 1, - .tx_mask_inverted = 1, + .tx_mask_normal = 1, }, [POLARIS_EVK] = { .is_polaris = 1, @@ -183,7 +188,12 @@ static const struct mceusb_model mceusb_model[] = { * to allow testing it */ .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW, - .name = "cx231xx MCE IR", + .name = "Conexant Hybrid TV (cx231xx) MCE IR", + }, + [CX_HYBRID_TV] = { + .is_polaris = 1, + .no_tx = 1, /* tx isn't wired up at all */ + .name = "Conexant Hybrid TV (cx231xx) MCE IR", }, }; @@ -273,6 +283,8 @@ static struct usb_device_id mceusb_dev_table[] = { { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) }, /* Formosa Industrial Computing */ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) }, + /* Fintek eHome Infrared Transceiver (HP branded) */ + { USB_DEVICE(VENDOR_FINTEK, 0x5168) }, /* Fintek eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_FINTEK, 0x0602) }, /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ @@ -292,9 +304,12 @@ static struct usb_device_id mceusb_dev_table[] = { { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, /* TiVo PC IR Receiver */ { USB_DEVICE(VENDOR_TIVO, 0x2000) }, - /* Conexant SDK */ + /* Conexant Hybrid TV "Shelby" Polaris SDK */ { USB_DEVICE(VENDOR_CONEXANT, 0x58a1), .driver_info = POLARIS_EVK }, + /* Conexant Hybrid TV RDU253S Polaris */ + { USB_DEVICE(VENDOR_CONEXANT, 0x58a5), + .driver_info = CX_HYBRID_TV }, /* Terminating entry */ { } }; @@ -303,7 +318,10 @@ static struct usb_device_id mceusb_dev_table[] = { struct mceusb_dev { /* ir-core bits */ struct ir_dev_props *props; - struct ir_raw_event rawir; + + /* optional features we can enable */ + bool carrier_report_enabled; + bool learning_enabled; /* core device bits */ struct device *dev; @@ -318,6 +336,8 @@ struct mceusb_dev { /* buffers and dma */ unsigned char *buf_in; unsigned int len_in; + dma_addr_t dma_in; + dma_addr_t dma_out; enum { CMD_HEADER = 0, @@ -325,15 +345,14 @@ struct mceusb_dev { CMD_DATA, PARSE_IRDATA, } parser_state; - u8 cmd, rem; /* Remaining IR data bytes in packet */ - dma_addr_t dma_in; - dma_addr_t dma_out; + u8 cmd, rem; /* Remaining IR data bytes in packet */ struct { u32 connected:1; - u32 tx_mask_inverted:1; + u32 tx_mask_normal:1; u32 microsoft_gen1:1; + u32 no_tx:1; } flags; /* transmit support */ @@ -408,9 +427,10 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd) case MCE_CMD_UNKNOWN: case MCE_CMD_S_CARRIER: case MCE_CMD_S_TIMEOUT: - case MCE_CMD_G_RXSENSOR: + case MCE_RSP_PULSE_COUNT: datasize = 2; break; + case MCE_CMD_SIG_END: case MCE_CMD_S_TXMASK: case MCE_CMD_S_RXSENSOR: datasize = 1; @@ -433,7 +453,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, return; /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ - if (ir->flags.microsoft_gen1 && !out) + if (ir->flags.microsoft_gen1 && !out && !offset) skip = 2; if (len <= skip) @@ -491,6 +511,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_COMMAND_HEADER: switch (subcmd) { + case MCE_CMD_SIG_END: + dev_info(dev, "End of signal\n"); + break; case MCE_CMD_PING: dev_info(dev, "Ping\n"); break; @@ -525,10 +548,11 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, inout, data1 == 0x02 ? "short" : "long"); break; case MCE_CMD_G_RXSENSOR: - if (len == 2) + /* aka MCE_RSP_PULSE_COUNT */ + if (out) dev_info(dev, "Get receive sensor\n"); - else - dev_info(dev, "Received pulse count is %d\n", + else if (ir->learning_enabled) + dev_info(dev, "RX pulse count: %d\n", ((data1 << 8) | data2)); break; case MCE_RSP_CMD_INVALID: @@ -724,16 +748,16 @@ out: return ret ? ret : n; } -/* Sets active IR outputs -- mce devices typically (all?) have two */ +/* Sets active IR outputs -- mce devices typically have two */ static int mceusb_set_tx_mask(void *priv, u32 mask) { struct mceusb_dev *ir = priv; - if (ir->flags.tx_mask_inverted) + if (ir->flags.tx_mask_normal) + ir->tx_mask = mask; + else ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ? mask ^ MCE_DEFAULT_TX_MASK : mask) << 1; - else - ir->tx_mask = mask; return 0; } @@ -752,7 +776,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) if (carrier == 0) { ir->carrier = carrier; - cmdbuf[2] = 0x01; + cmdbuf[2] = MCE_CMD_SIG_END; cmdbuf[3] = MCE_IRDATA_TRAILER; dev_dbg(ir->dev, "%s: disabling carrier " "modulation\n", __func__); @@ -782,6 +806,34 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) return carrier; } +/* + * We don't do anything but print debug spew for many of the command bits + * we receive from the hardware, but some of them are useful information + * we want to store so that we can use them. + */ +static void mceusb_handle_command(struct mceusb_dev *ir, int index) +{ + u8 hi = ir->buf_in[index + 1] & 0xff; + u8 lo = ir->buf_in[index + 2] & 0xff; + + switch (ir->buf_in[index]) { + /* 2-byte return value commands */ + case MCE_CMD_S_TIMEOUT: + ir->props->timeout = MS_TO_NS((hi << 8 | lo) / 2); + break; + + /* 1-byte return value commands */ + case MCE_CMD_S_TXMASK: + ir->tx_mask = hi; + break; + case MCE_CMD_S_RXSENSOR: + ir->learning_enabled = (hi == 0x02); + break; + default: + break; + } +} + static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) { DEFINE_IR_RAW_EVENT(rawir); @@ -791,39 +843,30 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) if (ir->flags.microsoft_gen1) i = 2; + /* if there's no data, just return now */ + if (buf_len <= i) + return; + for (; i < buf_len; i++) { switch (ir->parser_state) { case SUBCMD: ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); mceusb_dev_printdata(ir, ir->buf_in, i - 1, ir->rem + 2, false); + mceusb_handle_command(ir, i); ir->parser_state = CMD_DATA; break; case PARSE_IRDATA: ir->rem--; rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) - * MCE_TIME_UNIT * 1000; - - if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { - if (ir->rawir.pulse == rawir.pulse) { - ir->rawir.duration += rawir.duration; - } else { - ir->rawir.duration = rawir.duration; - ir->rawir.pulse = rawir.pulse; - } - if (ir->rem) - break; - } - rawir.duration += ir->rawir.duration; - ir->rawir.duration = 0; - ir->rawir.pulse = rawir.pulse; + * MS_TO_NS(MCE_TIME_UNIT); dev_dbg(ir->dev, "Storing %s with duration %d\n", rawir.pulse ? "pulse" : "space", rawir.duration); - ir_raw_event_store(ir->idev, &rawir); + ir_raw_event_store_with_filter(ir->idev, &rawir); break; case CMD_DATA: ir->rem--; @@ -839,17 +882,10 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) continue; } ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); - mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false); - if (ir->rem) { + mceusb_dev_printdata(ir, ir->buf_in, + i, ir->rem + 1, false); + if (ir->rem) ir->parser_state = PARSE_IRDATA; - break; - } - /* - * a package with len=0 (e. g. 0x80) means end of - * data. We could use it to do the call to - * ir_raw_event_handle(). For now, we don't need to - * use it. - */ break; } @@ -984,9 +1020,11 @@ static void mceusb_get_parameters(struct mceusb_dev *ir) mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ)); mce_sync_in(ir, NULL, maxp); - /* get the transmitter bitmask */ - mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); - mce_sync_in(ir, NULL, maxp); + if (!ir->flags.no_tx) { + /* get the transmitter bitmask */ + mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK)); + mce_sync_in(ir, NULL, maxp); + } /* get receiver timeout value */ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT)); @@ -1035,12 +1073,18 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) props->priv = ir; props->driver_type = RC_DRIVER_IR_RAW; props->allowed_protos = IR_TYPE_ALL; - props->s_tx_mask = mceusb_set_tx_mask; - props->s_tx_carrier = mceusb_set_tx_carrier; - props->tx_ir = mceusb_tx_ir; + props->timeout = MS_TO_NS(1000); + if (!ir->flags.no_tx) { + props->s_tx_mask = mceusb_set_tx_mask; + props->s_tx_carrier = mceusb_set_tx_carrier; + props->tx_ir = mceusb_tx_ir; + } ir->props = props; + usb_to_input_id(ir->usbdev, &idev->id); + idev->dev.parent = ir->dev; + if (mceusb_model[ir->model].rc_map) rc_map = mceusb_model[ir->model].rc_map; @@ -1074,16 +1118,16 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, enum mceusb_model_type model = id->driver_info; bool is_gen3; bool is_microsoft_gen1; - bool tx_mask_inverted; + bool tx_mask_normal; bool is_polaris; - dev_dbg(&intf->dev, ": %s called\n", __func__); + dev_dbg(&intf->dev, "%s called\n", __func__); idesc = intf->cur_altsetting; is_gen3 = mceusb_model[model].mce_gen3; is_microsoft_gen1 = mceusb_model[model].mce_gen1; - tx_mask_inverted = mceusb_model[model].tx_mask_inverted; + tx_mask_normal = mceusb_model[model].tx_mask_normal; is_polaris = mceusb_model[model].is_polaris; if (is_polaris) { @@ -1107,7 +1151,7 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_in = ep; ep_in->bmAttributes = USB_ENDPOINT_XFER_INT; ep_in->bInterval = 1; - dev_dbg(&intf->dev, ": acceptable inbound endpoint " + dev_dbg(&intf->dev, "acceptable inbound endpoint " "found\n"); } @@ -1122,12 +1166,12 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ep_out = ep; ep_out->bmAttributes = USB_ENDPOINT_XFER_INT; ep_out->bInterval = 1; - dev_dbg(&intf->dev, ": acceptable outbound endpoint " + dev_dbg(&intf->dev, "acceptable outbound endpoint " "found\n"); } } if (ep_in == NULL) { - dev_dbg(&intf->dev, ": inbound and/or endpoint not found\n"); + dev_dbg(&intf->dev, "inbound and/or endpoint not found\n"); return -ENODEV; } @@ -1150,11 +1194,10 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, ir->dev = &intf->dev; ir->len_in = maxp; ir->flags.microsoft_gen1 = is_microsoft_gen1; - ir->flags.tx_mask_inverted = tx_mask_inverted; + ir->flags.tx_mask_normal = tx_mask_normal; + ir->flags.no_tx = mceusb_model[model].no_tx; ir->model = model; - init_ir_raw_event(&ir->rawir); - /* Saving usb interface data for use by the transmitter routine */ ir->usb_ep_in = ep_in; ir->usb_ep_out = ep_out; @@ -1191,7 +1234,8 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, mceusb_get_parameters(ir); - mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK); + if (!ir->flags.no_tx) + mceusb_set_tx_mask(ir, MCE_DEFAULT_TX_MASK); usb_set_intfdata(intf, ir); diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/IR/nuvoton-cir.c index 301be53aee85..acc729c79cec 100644 --- a/drivers/media/IR/nuvoton-cir.c +++ b/drivers/media/IR/nuvoton-cir.c @@ -603,6 +603,8 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) count = nvt->pkts; nvt_dbg_verbose("Processing buffer of len %d", count); + init_ir_raw_event(&rawir); + for (i = 0; i < count; i++) { nvt->pkts--; sample = nvt->buf[i]; @@ -643,11 +645,15 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) * indicates end of IR signal, but new data incoming. In both * cases, it means we're ready to call ir_raw_event_handle */ - if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) && - (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE)) + if ((sample == BUF_PULSE_BIT) && nvt->pkts) { + nvt_dbg("Calling ir_raw_event_handle (signal end)\n"); ir_raw_event_handle(nvt->rdev); + } } + nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n"); + ir_raw_event_handle(nvt->rdev); + if (nvt->pkts) { nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts); nvt->pkts = 0; diff --git a/drivers/media/IR/streamzap.c b/drivers/media/IR/streamzap.c index 548381c35bfd..3a20aef67d08 100644 --- a/drivers/media/IR/streamzap.c +++ b/drivers/media/IR/streamzap.c @@ -34,8 +34,9 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/usb.h> #include <linux/input.h> +#include <linux/usb.h> +#include <linux/usb/input.h> #include <media/ir-core.h> #define DRIVER_VERSION "1.61" @@ -140,7 +141,9 @@ static struct usb_driver streamzap_driver = { static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) { - ir_raw_event_store(sz->idev, &rawir); + dev_dbg(sz->dev, "Storing %s with duration %u us\n", + (rawir.pulse ? "pulse" : "space"), rawir.duration); + ir_raw_event_store_with_filter(sz->idev, &rawir); } static void sz_push_full_pulse(struct streamzap_ir *sz, @@ -167,7 +170,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, rawir.duration *= 1000; rawir.duration &= IR_MAX_DURATION; } - dev_dbg(sz->dev, "ls %u\n", rawir.duration); sz_push(sz, rawir); sz->idle = false; @@ -180,7 +182,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, sz->sum += rawir.duration; rawir.duration *= 1000; rawir.duration &= IR_MAX_DURATION; - dev_dbg(sz->dev, "p %u\n", rawir.duration); sz_push(sz, rawir); } @@ -200,7 +201,6 @@ static void sz_push_full_space(struct streamzap_ir *sz, rawir.duration += SZ_RESOLUTION / 2; sz->sum += rawir.duration; rawir.duration *= 1000; - dev_dbg(sz->dev, "s %u\n", rawir.duration); sz_push(sz, rawir); } @@ -221,8 +221,6 @@ static void streamzap_callback(struct urb *urb) struct streamzap_ir *sz; unsigned int i; int len; - static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) & - IR_MAX_DURATION) | 0x03000000); if (!urb) return; @@ -246,7 +244,7 @@ static void streamzap_callback(struct urb *urb) dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); for (i = 0; i < len; i++) { - dev_dbg(sz->dev, "sz idx %d: %x\n", + dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n", i, (unsigned char)sz->buf_in[i]); switch (sz->decoder_state) { case PulseSpace: @@ -273,7 +271,7 @@ static void streamzap_callback(struct urb *urb) DEFINE_IR_RAW_EVENT(rawir); rawir.pulse = false; - rawir.duration = timeout; + rawir.duration = sz->props->timeout; sz->idle = true; if (sz->timeout_enabled) sz_push(sz, rawir); @@ -335,6 +333,9 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz) sz->props = props; + usb_to_input_id(sz->usbdev, &idev->id); + idev->dev.parent = sz->dev; + ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME); if (ret < 0) { dev_err(dev, "remote input device register failed\n"); @@ -444,6 +445,8 @@ static int __devinit streamzap_probe(struct usb_interface *intf, sz->decoder_state = PulseSpace; /* FIXME: don't yet have a way to set this */ sz->timeout_enabled = true; + sz->props->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) & + IR_MAX_DURATION) | 0x03000000); #if 0 /* not yet supported, depends on patches from maxim */ /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c index 05bde9ccb770..1d1d8d200755 100644 --- a/drivers/media/common/saa7146_hlp.c +++ b/drivers/media/common/saa7146_hlp.c @@ -558,7 +558,7 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat) { struct saa7146_vv *vv = dev->vv_data; - struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat); int b_depth = vv->ov_fmt->depth; int b_bpl = vv->ov_fb.fmt.bytesperline; @@ -702,7 +702,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71 struct saa7146_vv *vv = dev->vv_data; struct saa7146_video_dma vdma1; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); int width = buf->fmt->width; int height = buf->fmt->height; @@ -827,7 +827,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71 struct saa7146_video_dma vdma2; struct saa7146_video_dma vdma3; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); int width = buf->fmt->width; int height = buf->fmt->height; @@ -994,7 +994,7 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar) void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next) { - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); struct saa7146_vv *vv = dev->vv_data; u32 vdma1_prot_addr; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 741c5732b430..d246910129e8 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -84,7 +84,7 @@ static struct saa7146_format formats[] = { static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format); -struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc) +struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc) { int i, j = NUM_FORMATS; @@ -266,7 +266,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); struct scatterlist *list = dma->sglist; int length = dma->sglen; - struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); @@ -408,7 +408,7 @@ static int video_begin(struct saa7146_fh *fh) } } - fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); @@ -460,7 +460,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file) return -EBUSY; } - fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); @@ -536,7 +536,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f return -EPERM; /* check args */ - fmt = format_by_fourcc(dev, fb->fmt.pixelformat); + fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat); if (NULL == fmt) return -EINVAL; @@ -760,7 +760,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); - fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat); + fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; @@ -1264,7 +1264,7 @@ static int buffer_prepare(struct videobuf_queue *q, buf->fmt = &fh->video_fmt; buf->vb.field = fh->video_fmt.field; - sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); + sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat); release_all_pagetables(dev, buf); if( 0 != IS_PLANAR(sfmt->trans)) { @@ -1378,7 +1378,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file) fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; fh->video_fmt.bytesperline = 0; fh->video_fmt.field = V4L2_FIELD_ANY; - sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); + sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; videobuf_queue_sg_init(&fh->video_q, &video_qops, diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 5bf4985daede..05e832f61c3e 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -361,7 +361,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations rtrack_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { @@ -412,13 +412,6 @@ static int __init rtrack_init(void) rt->vdev.release = video_device_release_empty; video_set_drvdata(&rt->vdev, rt); - if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(&rt->v4l2_dev); - release_region(rt->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); - /* Set up the I/O locking */ mutex_init(&rt->lock); @@ -430,6 +423,13 @@ static int __init rtrack_init(void) sleep_delay(2000000); /* make sure it's totally down */ outb(0xc0, rt->io); /* steady volume, mute card */ + if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); + return 0; } diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index c22311393624..dd8a6ab0d437 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, static const struct v4l2_file_operations aztech_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops aztech_ioctl_ops = { @@ -375,6 +375,8 @@ static int __init aztech_init(void) az->vdev.ioctl_ops = &aztech_ioctl_ops; az->vdev.release = video_device_release_empty; video_set_drvdata(&az->vdev, az); + /* mute card - prevents noisy bootups */ + outb(0, az->io); if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); @@ -383,8 +385,6 @@ static int __init aztech_init(void) } v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); - /* mute card - prevents noisy bootups */ - outb(0, az->io); return 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index b701ea6e7c73..bc9ad0897c55 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo unsigned char readbuf[RDS_BUFFER]; int i = 0; + mutex_lock(&dev->lock); if (dev->rdsstat == 0) { - mutex_lock(&dev->lock); dev->rdsstat = 1; outb(0x80, dev->io); /* Select RDS fifo */ - mutex_unlock(&dev->lock); init_timer(&dev->readtimer); dev->readtimer.function = cadet_handler; dev->readtimer.data = (unsigned long)dev; @@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo add_timer(&dev->readtimer); } if (dev->rdsin == dev->rdsout) { + mutex_unlock(&dev->lock); if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; interruptible_sleep_on(&dev->read_queue); + mutex_lock(&dev->lock); } while (i < count && dev->rdsin != dev->rdsout) readbuf[i++] = dev->rdsbuf[dev->rdsout++]; + mutex_unlock(&dev->lock); if (copy_to_user(data, readbuf, i)) return -EFAULT; @@ -525,9 +527,11 @@ static int cadet_open(struct file *file) { struct cadet *dev = video_drvdata(file); + mutex_lock(&dev->lock); dev->users++; if (1 == dev->users) init_waitqueue_head(&dev->read_queue); + mutex_unlock(&dev->lock); return 0; } @@ -535,11 +539,13 @@ static int cadet_release(struct file *file) { struct cadet *dev = video_drvdata(file); + mutex_lock(&dev->lock); dev->users--; if (0 == dev->users) { del_timer_sync(&dev->readtimer); dev->rdsstat = 0; } + mutex_unlock(&dev->lock); return 0; } @@ -559,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = { .open = cadet_open, .release = cadet_release, .read = cadet_read, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = cadet_poll, }; diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 79039674a0e0..28fa85ba2087 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(pci, gemtek_pci_id); static const struct v4l2_file_operations gemtek_pci_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { @@ -422,11 +422,11 @@ static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_dev card->vdev.release = video_device_release_empty; video_set_drvdata(&card->vdev, card); + gemtek_pci_mute(card); + if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0) goto err_video; - gemtek_pci_mute(card); - v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", pdev->revision, card->iobase, card->iobase + card->length - 1); diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 73985f641f07..259936422e49 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt) static const struct v4l2_file_operations gemtek_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int vidioc_querycap(struct file *file, void *priv, @@ -577,12 +577,6 @@ static int __init gemtek_init(void) gt->vdev.release = video_device_release_empty; video_set_drvdata(>->vdev, gt); - if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(gt->io, 1); - return -EBUSY; - } - /* Set defaults */ gt->lastfreq = GEMTEK_LOWFREQ; gt->bu2614data = 0; @@ -590,6 +584,12 @@ static int __init gemtek_init(void) if (initmute) gemtek_mute(gt); + if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(gt->io, 1); + return -EBUSY; + } + return 0; } diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 08f1051979ca..6af61bfeb178 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations maestro_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops maestro_ioctl_ops = { @@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev, dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + if (!radio_power_on(dev)) { + retval = -EIO; + goto errfr1; + } + retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); if (retval) { v4l2_err(v4l2_dev, "can't register video device!\n"); goto errfr1; } - if (!radio_power_on(dev)) { - retval = -EIO; - goto errunr; - } - v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); return 0; -errunr: - video_unregister_device(&dev->vdev); errfr1: v4l2_device_unregister(v4l2_dev); errfr: diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 255d40df4b46..6459a220b0dd 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, static const struct v4l2_file_operations maxiradio_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 4ff885445fd4..3fb76e3834c9 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -33,6 +33,7 @@ struct pcm20 { unsigned long freq; int muted; struct snd_miro_aci *aci; + struct mutex lock; }; static struct pcm20 pcm20_card = { @@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq) static const struct v4l2_file_operations pcm20_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int vidioc_querycap(struct file *file, void *priv, @@ -229,7 +230,7 @@ static int __init pcm20_init(void) return -ENODEV; } strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name)); - + mutex_init(&dev->lock); res = v4l2_device_register(NULL, v4l2_dev); if (res < 0) { @@ -242,6 +243,7 @@ static int __init pcm20_init(void) dev->vdev.fops = &pcm20_fops; dev->vdev.ioctl_ops = &pcm20_ioctl_ops; dev->vdev.release = video_device_release_empty; + dev->vdev.lock = &dev->lock; video_set_drvdata(&dev->vdev, dev); if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index a79296aac9a9..8d6ea591bd18 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations rtrack2_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { @@ -315,6 +315,10 @@ static int __init rtrack2_init(void) dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + /* mute card - prevents noisy bootups */ + outb(1, dev->io); + dev->muted = 1; + mutex_init(&dev->lock); if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); @@ -324,10 +328,6 @@ static int __init rtrack2_init(void) v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); - /* mute card - prevents noisy bootups */ - outb(1, dev->io); - dev->muted = 1; - return 0; } diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 985359d18aa5..b5a5f89e238a 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations fmi_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops fmi_ioctl_ops = { @@ -382,6 +382,9 @@ static int __init fmi_init(void) mutex_init(&fmi->lock); + /* mute card - prevents noisy bootups */ + fmi_mute(fmi); + if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); release_region(fmi->io, 2); @@ -391,8 +394,6 @@ static int __init fmi_init(void) } v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); - /* mute card - prevents noisy bootups */ - fmi_mute(fmi); return 0; } diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 52c7bbb32b8b..dc3f04c52d5e 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations fmr2_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { @@ -424,6 +424,10 @@ static int __init fmr2_init(void) fmr2->vdev.release = video_device_release_empty; video_set_drvdata(&fmr2->vdev, fmr2); + /* mute card - prevents noisy bootups */ + fmr2_mute(fmr2->io); + fmr2_product_info(fmr2); + if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); release_region(fmr2->io, 2); @@ -431,11 +435,6 @@ static int __init fmr2_init(void) } v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); - /* mute card - prevents noisy bootups */ - mutex_lock(&fmr2->lock); - fmr2_mute(fmr2->io); - fmr2_product_info(fmr2); - mutex_unlock(&fmr2->lock); debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); return 0; } diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 03829e6818bd..726d367ad8d0 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -53,7 +53,8 @@ struct radio_si4713_device { /* radio_si4713_fops - file operations interface */ static const struct v4l2_file_operations radio_si4713_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + /* Note: locking is done at the subdev level in the i2c driver. */ + .unlocked_ioctl = video_ioctl2, }; /* Video4Linux Interface */ diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 789d2ec66e19..0e71d816c725 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -142,7 +142,6 @@ struct tea5764_device { struct video_device *videodev; struct tea5764_regs regs; struct mutex mutex; - int users; }; /* I2C code related */ @@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv, return 0; } -static int tea5764_open(struct file *file) -{ - /* Currently we support only one device */ - struct tea5764_device *radio = video_drvdata(file); - - mutex_lock(&radio->mutex); - /* Only exclusive access */ - if (radio->users) { - mutex_unlock(&radio->mutex); - return -EBUSY; - } - radio->users++; - mutex_unlock(&radio->mutex); - file->private_data = radio; - return 0; -} - -static int tea5764_close(struct file *file) -{ - struct tea5764_device *radio = video_drvdata(file); - - if (!radio) - return -ENODEV; - mutex_lock(&radio->mutex); - radio->users--; - mutex_unlock(&radio->mutex); - return 0; -} - /* File system interface */ static const struct v4l2_file_operations tea5764_fops = { .owner = THIS_MODULE, - .open = tea5764_open, - .release = tea5764_close, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops tea5764_ioctl_ops = { @@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, int ret; PDEBUG("probe"); - radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL); + radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL); if (!radio) return -ENOMEM; @@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, radio); video_set_drvdata(radio->videodev, radio); - - ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (ret < 0) { - PWARN("Could not register video device!"); - goto errrel; - } + radio->videodev->lock = &radio->mutex; /* initialize and power off the chip */ tea5764_i2c_read(radio); @@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client, tea5764_mute(radio, 1); tea5764_power_down(radio); + ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (ret < 0) { + PWARN("Could not register video device!"); + goto errrel; + } + PINFO("registered."); return 0; errrel: diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index fc1c860fd438..a32663917059 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations terratec_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops terratec_ioctl_ops = { @@ -389,6 +389,9 @@ static int __init terratec_init(void) mutex_init(&tt->lock); + /* mute card - prevents noisy bootups */ + tt_write_vol(tt, 0); + if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(&tt->v4l2_dev); release_region(tt->io, 2); @@ -396,9 +399,6 @@ static int __init terratec_init(void) } v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); - - /* mute card - prevents noisy bootups */ - tt_write_vol(tt, 0); return 0; } diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index b8bb3ef47df5..a185610b376b 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -34,6 +34,7 @@ struct timbradio { struct v4l2_subdev *sd_dsp; struct video_device video_dev; struct v4l2_device v4l2_dev; + struct mutex lock; }; @@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = { static const struct v4l2_file_operations timbradio_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int __devinit timbradio_probe(struct platform_device *pdev) @@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) } tr->pdata = *pdata; + mutex_init(&tr->lock); strlcpy(tr->video_dev.name, "Timberdale Radio", sizeof(tr->video_dev.name)); @@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev) tr->video_dev.ioctl_ops = &timbradio_ioctl_ops; tr->video_dev.release = video_device_release_empty; tr->video_dev.minor = -1; + tr->video_dev.lock = &tr->lock; strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); err = v4l2_device_register(NULL, &tr->v4l2_dev); diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 9d6dcf8af5b0..22fa9cc28abe 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations trust_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops trust_ioctl_ops = { @@ -396,14 +396,6 @@ static int __init trust_init(void) tr->vdev.release = video_device_release_empty; video_set_drvdata(&tr->vdev, tr); - if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(tr->io, 2); - return -EINVAL; - } - - v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); - write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ @@ -418,6 +410,14 @@ static int __init trust_init(void) /* mute card - prevents noisy bootups */ tr_setmute(tr, 1); + if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(tr->io, 2); + return -EINVAL; + } + + v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); + return 0; } diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index b1f630527dc1..8dbbf08f2207 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -317,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv) static const struct v4l2_file_operations typhoon_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { @@ -344,18 +344,18 @@ static int __init typhoon_init(void) strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); dev->io = io; - dev->curfreq = dev->mutefreq = mutefreq; if (dev->io == -1) { v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); return -EINVAL; } - if (dev->mutefreq < 87000 || dev->mutefreq > 108500) { + if (mutefreq < 87000 || mutefreq > 108500) { v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); return -EINVAL; } + dev->curfreq = dev->mutefreq = mutefreq << 4; mutex_init(&dev->lock); if (!request_region(dev->io, 8, "typhoon")) { @@ -378,17 +378,17 @@ static int __init typhoon_init(void) dev->vdev.ioctl_ops = &typhoon_ioctl_ops; dev->vdev.release = video_device_release_empty; video_set_drvdata(&dev->vdev, dev); + + /* mute card - prevents noisy bootups */ + typhoon_mute(dev); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(&dev->v4l2_dev); release_region(dev->io, 8); return -EINVAL; } v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); - v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq); - dev->mutefreq <<= 4; - - /* mute card - prevents noisy bootups */ - typhoon_mute(dev); + v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq); return 0; } diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index f31eab99c943..af99c5bd88c1 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static const struct v4l2_file_operations zoltrix_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { @@ -424,20 +424,6 @@ static int __init zoltrix_init(void) return res; } - strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); - zol->vdev.v4l2_dev = v4l2_dev; - zol->vdev.fops = &zoltrix_fops; - zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; - zol->vdev.release = video_device_release_empty; - video_set_drvdata(&zol->vdev, zol); - - if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { - v4l2_device_unregister(v4l2_dev); - release_region(zol->io, 2); - return -EINVAL; - } - v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); - mutex_init(&zol->lock); /* mute card - prevents noisy bootups */ @@ -452,6 +438,20 @@ static int __init zoltrix_init(void) zol->curvol = 0; zol->stereo = 1; + strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); + zol->vdev.v4l2_dev = v4l2_dev; + zol->vdev.fops = &zoltrix_fops; + zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; + zol->vdev.release = video_device_release_empty; + video_set_drvdata(&zol->vdev, zol); + + if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(zol->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); + return 0; } diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 31e7a123d19a..f989f2820d88 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar) static const struct v4l2_file_operations ar_fops = { .owner = THIS_MODULE, .read = ar_read, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops ar_ioctl_ops = { diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a529619e51f6..0902ec041c7a 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -854,7 +854,6 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM; /* is it free? */ - mutex_lock(&btv->lock); if (btv->resources & xbits) { /* no, someone else uses it */ goto fail; @@ -884,11 +883,9 @@ int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit) /* it's free, grab it */ fh->resources |= bit; btv->resources |= bit; - mutex_unlock(&btv->lock); return 1; fail: - mutex_unlock(&btv->lock); return 0; } @@ -940,7 +937,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) /* trying to free ressources not allocated by us ... */ printk("bttv: BUG! (btres)\n"); } - mutex_lock(&btv->lock); fh->resources &= ~bits; btv->resources &= ~bits; @@ -951,8 +947,6 @@ void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits) if (0 == (bits & VBI_RESOURCES)) disclaim_vbi_lines(btv); - - mutex_unlock(&btv->lock); } /* ----------------------------------------------------------------------- */ @@ -1713,28 +1707,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, /* Make sure tvnorm and vbi_end remain consistent until we're done. */ - mutex_lock(&btv->lock); norm = btv->tvnorm; /* In this mode capturing always starts at defrect.top (default VDELAY), ignoring cropping parameters. */ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) { - mutex_unlock(&btv->lock); return -EINVAL; } - mutex_unlock(&btv->lock); - c.rect = bttv_tvnorms[norm].cropcap.defrect; } else { - mutex_lock(&btv->lock); - norm = btv->tvnorm; c = btv->crop[!!fh->do_crop]; - mutex_unlock(&btv->lock); - if (width < c.min_scaled_width || width > c.max_scaled_width || height < c.min_scaled_height) @@ -1858,7 +1844,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) unsigned int i; int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (err) goto err; @@ -1874,7 +1859,6 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) set_tvnorm(btv, i); err: - mutex_unlock(&btv->lock); return err; } @@ -1898,7 +1882,6 @@ static int bttv_enum_input(struct file *file, void *priv, struct bttv *btv = fh->btv; int rc = 0; - mutex_lock(&btv->lock); if (i->index >= bttv_tvcards[btv->c.type].video_inputs) { rc = -EINVAL; goto err; @@ -1928,7 +1911,6 @@ static int bttv_enum_input(struct file *file, void *priv, i->std = BTTV_NORMS; err: - mutex_unlock(&btv->lock); return rc; } @@ -1938,9 +1920,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i) struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *i = btv->input; - mutex_unlock(&btv->lock); return 0; } @@ -1952,7 +1932,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) int err; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err; @@ -1965,7 +1944,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) set_input(btv, i, btv->tvnorm); err: - mutex_unlock(&btv->lock); return 0; } @@ -1979,7 +1957,6 @@ static int bttv_s_tuner(struct file *file, void *priv, if (unlikely(0 != t->index)) return -EINVAL; - mutex_lock(&btv->lock); if (unlikely(btv->tuner_type == TUNER_ABSENT)) { err = -EINVAL; goto err; @@ -1995,7 +1972,6 @@ static int bttv_s_tuner(struct file *file, void *priv, btv->audio_mode_gpio(btv, t, 1); err: - mutex_unlock(&btv->lock); return 0; } @@ -2006,10 +1982,8 @@ static int bttv_g_frequency(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = btv->freq; - mutex_unlock(&btv->lock); return 0; } @@ -2024,7 +1998,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&btv->lock); err = v4l2_prio_check(&btv->prio, fh->prio); if (unlikely(err)) goto err; @@ -2039,7 +2012,6 @@ static int bttv_s_frequency(struct file *file, void *priv, if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv, btv->freq); err: - mutex_unlock(&btv->lock); return 0; } @@ -2172,7 +2144,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, /* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. */ - mutex_lock(&btv->lock); b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; @@ -2250,7 +2221,6 @@ limit_scaled_size_lock (struct bttv_fh * fh, rc = 0; /* success */ fail: - mutex_unlock(&btv->lock); return rc; } @@ -2282,9 +2252,7 @@ verify_window_lock (struct bttv_fh * fh, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&fh->btv->lock); height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&fh->btv->lock); field = (win->w.height > height2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; @@ -2360,7 +2328,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, } } - mutex_lock(&fh->cap.vb_lock); /* clip against screen */ if (NULL != btv->fbuf.base) n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height, @@ -2391,13 +2358,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, fh->ov.field = win->field; fh->ov.setup_ok = 1; - /* - * FIXME: btv is protected by btv->lock mutex, while btv->init - * is protected by fh->cap.vb_lock. This seems to open the - * possibility for some race situations. Maybe the better would - * be to unify those locks or to use another way to store the - * init values that will be consumed by videobuf callbacks - */ btv->init.ov.w.width = win->w.width; btv->init.ov.w.height = win->w.height; btv->init.ov.field = win->field; @@ -2412,7 +2372,6 @@ static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2526,9 +2485,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, if (V4L2_FIELD_ANY == field) { __s32 height2; - mutex_lock(&btv->lock); height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - mutex_unlock(&btv->lock); field = (f->fmt.pix.height > height2) ? V4L2_FIELD_INTERLACED : V4L2_FIELD_BOTTOM; @@ -2614,7 +2571,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ - mutex_lock(&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; @@ -2623,7 +2579,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.vb_lock); return 0; } @@ -2649,11 +2604,9 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) unsigned int i; struct bttv_fh *fh = priv; - mutex_lock(&fh->cap.vb_lock); retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) { - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2665,7 +2618,6 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - mutex_unlock(&fh->cap.vb_lock); return 0; } #endif @@ -2775,10 +2727,8 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) int retval = 0; if (on) { - mutex_lock(&fh->cap.vb_lock); /* verify args */ if (unlikely(!btv->fbuf.base)) { - mutex_unlock(&fh->cap.vb_lock); return -EINVAL; } if (unlikely(!fh->ov.setup_ok)) { @@ -2787,13 +2737,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) } if (retval) return retval; - mutex_unlock(&fh->cap.vb_lock); } if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY)) return -EBUSY; - mutex_lock(&fh->cap.vb_lock); if (on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_sg_alloc(sizeof(*new)); @@ -2805,7 +2753,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) /* switch over */ retval = bttv_switch_overlay(btv, fh, new); - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2844,7 +2791,6 @@ static int bttv_s_fbuf(struct file *file, void *f, } /* ok, accept it */ - mutex_lock(&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height; @@ -2876,7 +2822,6 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = bttv_switch_overlay(btv, fh, new); } } - mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2955,7 +2900,6 @@ static int bttv_queryctrl(struct file *file, void *priv, c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; - mutex_lock(&btv->lock); if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) *c = no_ctl; else { @@ -2963,7 +2907,6 @@ static int bttv_queryctrl(struct file *file, void *priv, *c = (NULL != ctrl) ? *ctrl : no_ctl; } - mutex_unlock(&btv->lock); return 0; } @@ -2974,10 +2917,8 @@ static int bttv_g_parm(struct file *file, void *f, struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); - mutex_unlock(&btv->lock); return 0; } @@ -2993,7 +2934,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); t->rxsubchans = V4L2_TUNER_SUB_MONO; bttv_call_all(btv, tuner, g_tuner, t); strcpy(t->name, "Television"); @@ -3005,7 +2945,6 @@ static int bttv_g_tuner(struct file *file, void *priv, if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); return 0; } @@ -3014,9 +2953,7 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) struct bttv_fh *fh = f; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); *p = v4l2_prio_max(&btv->prio); - mutex_unlock(&btv->lock); return 0; } @@ -3028,9 +2965,7 @@ static int bttv_s_priority(struct file *file, void *f, struct bttv *btv = fh->btv; int rc; - mutex_lock(&btv->lock); rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - mutex_unlock(&btv->lock); return rc; } @@ -3045,9 +2980,7 @@ static int bttv_cropcap(struct file *file, void *priv, cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) return -EINVAL; - mutex_lock(&btv->lock); *cap = bttv_tvnorms[btv->tvnorm].cropcap; - mutex_unlock(&btv->lock); return 0; } @@ -3065,9 +2998,7 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) inconsistent with fh->width or fh->height and apps do not expect a change here. */ - mutex_lock(&btv->lock); crop->c = btv->crop[!!fh->do_crop].rect; - mutex_unlock(&btv->lock); return 0; } @@ -3091,17 +3022,14 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) /* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. Note read() may change vbi_end in check_alloc_btres_lock(). */ - mutex_lock(&btv->lock); retval = v4l2_prio_check(&btv->prio, fh->prio); if (0 != retval) { - mutex_unlock(&btv->lock); return retval; } retval = -EBUSY; if (locked_btres(fh->btv, VIDEO_RESOURCES)) { - mutex_unlock(&btv->lock); return retval; } @@ -3113,7 +3041,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) b_top = max(b->top, btv->vbi_end); if (b_top + 32 >= b_bottom) { - mutex_unlock(&btv->lock); return retval; } @@ -3136,12 +3063,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->crop[1] = c; - mutex_unlock(&btv->lock); - fh->do_crop = 1; - mutex_lock(&fh->cap.vb_lock); - if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width; btv->init.width = c.min_scaled_width; @@ -3158,8 +3081,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } - mutex_unlock(&fh->cap.vb_lock); - return 0; } @@ -3227,7 +3148,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) return videobuf_poll_stream(file, &fh->vbi, wait); } - mutex_lock(&fh->cap.vb_lock); if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { /* streaming capture */ if (list_empty(&fh->cap.stream)) @@ -3262,7 +3182,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) else rc = 0; err: - mutex_unlock(&fh->cap.vb_lock); return rc; } @@ -3293,23 +3212,11 @@ static int bttv_open(struct file *file) return -ENOMEM; file->private_data = fh; - /* - * btv is protected by btv->lock mutex, while btv->init and other - * streaming vars are protected by fh->cap.vb_lock. We need to take - * care of both locks to avoid troubles. However, vb_lock is used also - * inside videobuf, without calling buf->lock. So, it is a very bad - * idea to hold both locks at the same time. - * Let's first copy btv->init at fh, holding cap.vb_lock, and then work - * with the rest of init, holding btv->lock. - */ - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); fh->type = type; fh->ov.setup_ok = 0; - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, @@ -3317,13 +3224,13 @@ static int bttv_open(struct file *file) V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops, &btv->c.pci->dev, &btv->s_lock, V4L2_BUF_TYPE_VBI_CAPTURE, V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), - fh, NULL); + fh, &btv->lock); set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm); @@ -3346,7 +3253,6 @@ static int bttv_open(struct file *file) bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); bttv_field_count(btv); - mutex_unlock(&btv->lock); return 0; } @@ -3355,7 +3261,6 @@ static int bttv_release(struct file *file) struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); /* turn off overlay */ if (check_btres(fh, RESOURCE_OVERLAY)) bttv_switch_overlay(btv,fh,NULL); @@ -3381,14 +3286,8 @@ static int bttv_release(struct file *file) /* free stuff */ - /* - * videobuf uses cap.vb_lock - we should avoid holding btv->lock, - * otherwise we may have dead lock conditions - */ - mutex_unlock(&btv->lock); videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh); @@ -3398,7 +3297,6 @@ static int bttv_release(struct file *file) if (!btv->users) audio_mute(btv, 1); - mutex_unlock(&btv->lock); return 0; } @@ -3502,11 +3400,8 @@ static int radio_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; file->private_data = fh; - mutex_lock(&fh->cap.vb_lock); *fh = btv->init; - mutex_unlock(&fh->cap.vb_lock); - mutex_lock(&btv->lock); v4l2_prio_open(&btv->prio, &fh->prio); btv->radio_user++; @@ -3514,7 +3409,6 @@ static int radio_open(struct file *file) bttv_call_all(btv, tuner, s_radio); audio_input(btv,TVAUDIO_INPUT_RADIO); - mutex_unlock(&btv->lock); return 0; } @@ -3524,7 +3418,6 @@ static int radio_release(struct file *file) struct bttv *btv = fh->btv; struct rds_command cmd; - mutex_lock(&btv->lock); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; kfree(fh); @@ -3532,7 +3425,6 @@ static int radio_release(struct file *file) btv->radio_user--; bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd); - mutex_unlock(&btv->lock); return 0; } @@ -3561,7 +3453,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL; if (0 != t->index) return -EINVAL; - mutex_lock(&btv->lock); strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; @@ -3570,8 +3461,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 0); - mutex_unlock(&btv->lock); - return 0; } @@ -3692,7 +3581,7 @@ static const struct v4l2_file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = radio_poll, }; diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 935e0c9a9674..c1193506131c 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -860,7 +860,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = qcam_read, }; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 6e4b19698c13..24fc00965a12 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -718,7 +718,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, static const struct v4l2_file_operations qcam_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = qcam_read, }; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 260c666ce931..0dfff50891e4 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1775,7 +1775,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = { .read = cafe_v4l_read, .poll = cafe_v4l_poll, .mmap = cafe_v4l_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c index 8f55692db36d..82d195be9197 100644 --- a/drivers/media/video/cx18/cx18-alsa-pcm.c +++ b/drivers/media/video/cx18/cx18-alsa-pcm.c @@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg) { - return snd_pcm_lib_ioctl(substream, cmd, arg); + struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); + int ret; + + snd_cx18_lock(cxsc); + ret = snd_pcm_lib_ioctl(substream, cmd, arg); + snd_cx18_unlock(cxsc); + return ret; } diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 9045f1ece0eb..ab461e27d9dd 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { .read = cx18_v4l2_read, .open = cx18_v4l2_open, /* FIXME change to video_ioctl2 if serialization lock can be removed */ - .ioctl = cx18_v4l2_ioctl, + .unlocked_ioctl = cx18_v4l2_ioctl, .release = cx18_v4l2_close, .poll = cx18_v4l2_enc_poll, }; diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index dfb198d0415b..f16461844c5c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1989,8 +1989,23 @@ static int cx25840_probe(struct i2c_client *client, v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, V4L2_CID_HUE, -128, 127, 1, 0); if (!is_cx2583x(state)) { - default_volume = 228 - cx25840_read(client, 0x8d4); - default_volume = ((default_volume / 2) + 23) << 9; + default_volume = cx25840_read(client, 0x8d4); + /* + * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume + * scale mapping limits to avoid -ERANGE errors when + * initializing the volume control + */ + if (default_volume > 228) { + /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ + default_volume = 228; + cx25840_write(client, 0x8d4, 228); + } + else if (default_volume < 20) { + /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ + default_volume = 20; + cx25840_write(client, 0x8d4, 20); + } + default_volume = (((228 - default_volume) >> 1) + 23) << 9; state->volume = v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 4aaa47c0eabf..54b7fcd469a8 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -40,7 +40,6 @@ #include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> -#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h" @@ -587,47 +586,26 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, int left, right, v, b; int changed = 0; u32 old; - struct v4l2_control client_ctl; - - /* Pass volume & balance onto any WM8775 */ - if (value->value.integer.value[0] >= value->value.integer.value[1]) { - v = value->value.integer.value[0] << 10; - b = value->value.integer.value[0] ? - (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] : - 0x8000; - } else { - v = value->value.integer.value[1] << 10; - b = value->value.integer.value[1] ? - 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] : - 0x8000; - } - client_ctl.value = v; - client_ctl.id = V4L2_CID_AUDIO_VOLUME; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - client_ctl.value = b; - client_ctl.id = V4L2_CID_AUDIO_BALANCE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); left = value->value.integer.value[0] & 0x3f; right = value->value.integer.value[1] & 0x3f; b = right - left; if (b < 0) { - v = 0x3f - left; - b = (-b) | 0x40; + v = 0x3f - left; + b = (-b) | 0x40; } else { - v = 0x3f - right; + v = 0x3f - right; } /* Do we really know this will always be called with IRQs on? */ spin_lock_irq(&chip->reg_lock); old = cx_read(AUD_VOL_CTL); if (v != (old & 0x3f)) { - cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v); - changed = 1; + cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; } - if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) { - cx_write(AUD_BAL_CTL, b); - changed = 1; + if (cx_read(AUD_BAL_CTL) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; } spin_unlock_irq(&chip->reg_lock); @@ -640,7 +618,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Analog-TV Volume", + .name = "Playback Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put, @@ -671,14 +649,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol = cx_read(AUD_VOL_CTL); if (value->value.integer.value[0] != !(vol & bit)) { vol ^= bit; - cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); - /* Pass mute onto any WM8775 */ - if ((1<<6) == bit) { - struct v4l2_control client_ctl; - client_ctl.value = 0 != (vol & bit); - client_ctl.id = V4L2_CID_AUDIO_MUTE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - } + cx_write(AUD_VOL_CTL, vol); ret = 1; } spin_unlock_irq(&chip->reg_lock); @@ -687,7 +658,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Audio-Out Switch", + .name = "Playback Switch", .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, @@ -696,49 +667,13 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = { static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog-TV Switch", + .name = "Capture Switch", .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1<<6), }; -static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); - value->value.integer.value[0] = client_ctl.value ? 1 : 0; - - return 0; -} - -static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - client_ctl.value = 0 != value->value.integer.value[0]; - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - return 0; -} - -static struct snd_kcontrol_new snd_cx88_alc_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Line-In ALC Switch", - .info = snd_ctl_boolean_mono_info, - .get = snd_cx88_alc_get, - .put = snd_cx88_alc_put, -}; - /**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/ @@ -860,7 +795,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, { struct snd_card *card; snd_cx88_card_t *chip; - struct v4l2_subdev *sd; int err; if (devno >= SNDRV_CARDS) @@ -896,15 +830,6 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, if (err < 0) goto error; - /* If there's a wm8775 then add a Line-In ALC switch */ - list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) { - if (WM8775_GID == sd->grp_id) { - snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, - chip)); - break; - } - } - strcpy (card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); sprintf(card->longname, "%s at %#llx", diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 9b9e169cce90..0ccc2afd7266 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1007,15 +1007,22 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, + /* 2: Line-In */ + .audioroute = 2, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + /* 2: Line-In */ + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + /* 2: Line-In */ + .audioroute = 2, }}, .mpeg = CX88_MPEG_DVB, }, diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 62cea9549404..d9249e5a04c9 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -40,7 +40,6 @@ #include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -#include <media/wm8775.h> MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -977,7 +976,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) const struct cx88_ctrl *c = NULL; u32 value,mask; int i; - struct v4l2_control client_ctl; for (i = 0; i < CX8800_CTLS; i++) { if (cx8800_ctls[i].v.id == ctl->id) { @@ -991,27 +989,6 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum; if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; - - /* Pass changes onto any WM8775 */ - client_ctl.id = ctl->id; - switch (ctl->id) { - case V4L2_CID_AUDIO_MUTE: - client_ctl.value = ctl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - client_ctl.value = (ctl->value) ? - (0x90 + ctl->value) << 8 : 0; - break; - case V4L2_CID_AUDIO_BALANCE: - client_ctl.value = ctl->value << 9; - break; - default: - client_ctl.id = 0; - break; - } - if (client_ctl.id) - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - mask=c->mask; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: @@ -1558,9 +1535,7 @@ static int radio_queryctrl (struct file *file, void *priv, if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE || - c->id == V4L2_CID_AUDIO_VOLUME || - c->id == V4L2_CID_AUDIO_BALANCE) { + if (c->id == V4L2_CID_AUDIO_MUTE) { for (i = 0; i < CX8800_CTLS; i++) { if (cx8800_ctls[i].v.id == c->id) break; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e8c732e7ae4f..c9981e77416a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -398,19 +398,17 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_hw(core, grpid, o, f, args...) \ +#define call_all(core, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) -#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) - struct cx8800_dev; struct cx8802_dev; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 908e3bc88303..2c3007280032 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -2377,7 +2377,7 @@ static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = em28xx_v4l2_open, .release = em28xx_v4l2_close, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index a5cfc76b40b7..bb164099ea2c 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -2530,7 +2530,7 @@ static const struct v4l2_file_operations et61x251_fops = { .owner = THIS_MODULE, .open = et61x251_open, .release = et61x251_release, - .ioctl = et61x251_ioctl, + .unlocked_ioctl = et61x251_ioctl, .read = et61x251_read, .poll = et61x251_poll, .mmap = et61x251_mmap, diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 330dadc00106..e23de57e2c73 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -63,7 +63,10 @@ struct sd { #define QUALITY_DEF 80 u8 jpegqual; /* webcam quality */ + u8 reg01; + u8 reg17; u8 reg18; + u8 flags; s8 ag_cnt; #define AG_CNT_START 13 @@ -96,6 +99,22 @@ enum sensors { SENSOR_SP80708, }; +/* device flags */ +#define PDN_INV 1 /* inverse pin S_PWR_DN / sn_xxx tables */ + +/* sn9c1xx definitions */ +/* register 0x01 */ +#define S_PWR_DN 0x01 /* sensor power down */ +#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */ +#define V_TX_EN 0x04 /* video transfer enable */ +#define LED 0x08 /* output to pin LED */ +#define SCL_SEL_OD 0x20 /* open-drain mode */ +#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */ +/* register 0x17 */ +#define MCK_SIZE_MASK 0x1f /* sensor master clock */ +#define SEN_CLK_EN 0x20 /* enable sensor clock */ +#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */ + /* V4L2 controls supported by the driver */ static void setbrightness(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev); @@ -1755,141 +1774,6 @@ static void po2030n_probe(struct gspca_dev *gspca_dev) } } -static void bridge_init(struct gspca_dev *gspca_dev, - const u8 *sn9c1xx) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 reg0102[2]; - const u8 *reg9a; - static const u8 reg9a_def[] = - {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; - static const u8 reg9a_spec[] = - {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; - static const u8 regd4[] = {0x60, 0x00, 0x00}; - - /* sensor clock already enabled in sd_init */ - /* reg_w1(gspca_dev, 0xf1, 0x00); */ - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - - /* configure gpio */ - reg0102[0] = sn9c1xx[1]; - reg0102[1] = sn9c1xx[2]; - if (gspca_dev->audio) - reg0102[1] |= 0x04; /* keep the audio connection */ - reg_w(gspca_dev, 0x01, reg0102, 2); - reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); - reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); - switch (sd->sensor) { - case SENSOR_GC0307: - case SENSOR_OV7660: - case SENSOR_PO1030: - case SENSOR_PO2030N: - case SENSOR_SOI768: - case SENSOR_SP80708: - reg9a = reg9a_spec; - break; - default: - reg9a = reg9a_def; - break; - } - reg_w(gspca_dev, 0x9a, reg9a, 6); - - reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); - - reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - - switch (sd->sensor) { - case SENSOR_ADCM1700: - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_GC0307: - msleep(50); - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x22); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - msleep(50); - break; - case SENSOR_MI0360B: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x60); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_MT9V111: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x61); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_OM6802: - msleep(10); - reg_w1(gspca_dev, 0x02, 0x73); - reg_w1(gspca_dev, 0x17, 0x60); - reg_w1(gspca_dev, 0x01, 0x22); - msleep(100); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x17, 0x64); - reg_w1(gspca_dev, 0x17, 0x64); - reg_w1(gspca_dev, 0x01, 0x42); - msleep(10); - reg_w1(gspca_dev, 0x01, 0x42); - i2c_w8(gspca_dev, om6802_init0[0]); - i2c_w8(gspca_dev, om6802_init0[1]); - msleep(15); - reg_w1(gspca_dev, 0x02, 0x71); - msleep(150); - break; - case SENSOR_OV7630: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0xe2); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_OV7648: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_PO1030: - case SENSOR_SOI768: - reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x60); - reg_w1(gspca_dev, 0x01, 0x40); - break; - case SENSOR_PO2030N: - case SENSOR_OV7660: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - break; - case SENSOR_SP80708: - reg_w1(gspca_dev, 0x01, 0x63); - reg_w1(gspca_dev, 0x17, 0x20); - reg_w1(gspca_dev, 0x01, 0x62); - reg_w1(gspca_dev, 0x01, 0x42); - msleep(100); - reg_w1(gspca_dev, 0x02, 0x62); - break; - default: -/* case SENSOR_HV7131R: */ -/* case SENSOR_MI0360: */ -/* case SENSOR_MO4000: */ - reg_w1(gspca_dev, 0x01, 0x43); - reg_w1(gspca_dev, 0x17, 0x61); - reg_w1(gspca_dev, 0x01, 0x42); - if (sd->sensor == SENSOR_HV7131R) - hv7131r_probe(gspca_dev); - break; - } -} - /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -1898,7 +1782,8 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; sd->bridge = id->driver_info >> 16; - sd->sensor = id->driver_info; + sd->sensor = id->driver_info >> 8; + sd->flags = id->driver_info; cam = &gspca_dev->cam; if (sd->sensor == SENSOR_ADCM1700) { @@ -1929,7 +1814,7 @@ static int sd_init(struct gspca_dev *gspca_dev) /* setup a selector by bridge */ reg_w1(gspca_dev, 0xf1, 0x01); reg_r(gspca_dev, 0x00, 1); - reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); + reg_w1(gspca_dev, 0xf1, 0x00); reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ regF1 = gspca_dev->usb_buf[0]; if (gspca_dev->usb_err < 0) @@ -2423,10 +2308,17 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; - u8 reg1, reg17; + u8 reg01, reg17; + u8 reg0102[2]; const u8 *sn9c1xx; const u8 (*init)[8]; + const u8 *reg9a; int mode; + static const u8 reg9a_def[] = + {0x00, 0x40, 0x20, 0x00, 0x00, 0x00}; + static const u8 reg9a_spec[] = + {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; + static const u8 regd4[] = {0x60, 0x00, 0x00}; static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; static const u8 CA_adcm1700[] = @@ -2448,7 +2340,85 @@ static int sd_start(struct gspca_dev *gspca_dev) /* initialize the bridge */ sn9c1xx = sn_tb[sd->sensor]; - bridge_init(gspca_dev, sn9c1xx); + + /* sensor clock already enabled in sd_init */ + /* reg_w1(gspca_dev, 0xf1, 0x00); */ + reg01 = sn9c1xx[1]; + if (sd->flags & PDN_INV) + reg01 ^= S_PDN_INV; /* power down inverted */ + reg_w1(gspca_dev, 0x01, reg01); + + /* configure gpio */ + reg0102[0] = reg01; + reg0102[1] = sn9c1xx[2]; + if (gspca_dev->audio) + reg0102[1] |= 0x04; /* keep the audio connection */ + reg_w(gspca_dev, 0x01, reg0102, 2); + reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2); + reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); + switch (sd->sensor) { + case SENSOR_GC0307: + case SENSOR_OV7660: + case SENSOR_PO1030: + case SENSOR_PO2030N: + case SENSOR_SOI768: + case SENSOR_SP80708: + reg9a = reg9a_spec; + break; + default: + reg9a = reg9a_def; + break; + } + reg_w(gspca_dev, 0x9a, reg9a, 6); + + reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); + + reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); + + reg17 = sn9c1xx[0x17]; + switch (sd->sensor) { + case SENSOR_GC0307: + msleep(50); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x02, 0x73); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg_w1(gspca_dev, 0x01, 0x22); + msleep(100); + reg01 = SCL_SEL_OD | S_PDN_INV; + reg17 &= MCK_SIZE_MASK; + reg17 |= 0x04; /* clock / 4 */ + break; + } + reg01 |= SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + reg17 |= SEN_CLK_EN; + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~S_PWR_DN; /* sensor power on */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~SYS_SEL_48M; + reg_w1(gspca_dev, 0x01, reg01); + + switch (sd->sensor) { + case SENSOR_HV7131R: + hv7131r_probe(gspca_dev); /*fixme: is it useful? */ + break; + case SENSOR_OM6802: + msleep(10); + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, om6802_init0[0]); + i2c_w8(gspca_dev, om6802_init0[1]); + msleep(15); + reg_w1(gspca_dev, 0x02, 0x71); + msleep(150); + break; + case SENSOR_SP80708: + msleep(100); + reg_w1(gspca_dev, 0x02, 0x62); + break; + } /* initialize the sensor */ i2c_w_seq(gspca_dev, sensor_init[sd->sensor]); @@ -2476,30 +2446,11 @@ static int sd_start(struct gspca_dev *gspca_dev) } reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); switch (sd->sensor) { - case SENSOR_GC0307: - reg17 = 0xa2; - break; - case SENSOR_MT9V111: - case SENSOR_MI0360B: - reg17 = 0xe0; - break; - case SENSOR_ADCM1700: - case SENSOR_OV7630: - reg17 = 0xe2; - break; - case SENSOR_OV7648: - reg17 = 0x20; - break; - case SENSOR_OV7660: - case SENSOR_SOI768: - reg17 = 0xa0; - break; - case SENSOR_PO1030: - case SENSOR_PO2030N: - reg17 = 0xa0; + case SENSOR_OM6802: +/* case SENSOR_OV7648: * fixme: sometimes */ break; default: - reg17 = 0x60; + reg17 |= DEF_EN; break; } reg_w1(gspca_dev, 0x17, reg17); @@ -2546,95 +2497,67 @@ static int sd_start(struct gspca_dev *gspca_dev) init = NULL; mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - if (mode) - reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */ - else - reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */ - reg17 = 0x61; /* 0x:20: enable sensor clock */ + reg01 |= SYS_SEL_48M | V_TX_EN; + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x02; /* clock / 2 */ switch (sd->sensor) { case SENSOR_ADCM1700: init = adcm1700_sensor_param1; - reg1 = 0x46; - reg17 = 0xe2; break; case SENSOR_GC0307: init = gc0307_sensor_param1; - reg17 = 0xa2; - reg1 = 0x44; + break; + case SENSOR_HV7131R: + case SENSOR_MI0360: + if (mode) + reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */ + else + reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ break; case SENSOR_MI0360B: init = mi0360b_sensor_param1; - reg1 &= ~0x02; /* don't inverse pin S_PWR_DN */ - reg17 = 0xe2; break; case SENSOR_MO4000: - if (mode) { -/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */ - reg1 = 0x06; /* clk 24Mz */ - } else { - reg17 = 0x22; /* 640 MCKSIZE */ -/* reg1 = 0x06; * 640 clk 24Mz (done) */ + if (mode) { /* if 320x240 */ + reg01 &= ~SYS_SEL_48M; /* clk 24Mz */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ } break; case SENSOR_MT9V111: init = mt9v111_sensor_param1; - if (mode) { - reg1 = 0x04; /* 320 clk 48Mhz */ - } else { -/* reg1 = 0x06; * 640 clk 24Mz (done) */ - reg17 = 0xc2; - } break; case SENSOR_OM6802: init = om6802_sensor_param1; - reg17 = 0x64; /* 640 MCKSIZE */ + if (!mode) { /* if 640x480 */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 4 */ + } break; case SENSOR_OV7630: init = ov7630_sensor_param1; - reg17 = 0xe2; - reg1 = 0x44; break; case SENSOR_OV7648: init = ov7648_sensor_param1; - reg17 = 0x21; -/* reg1 = 0x42; * 42 - 46? */ + reg17 &= ~MCK_SIZE_MASK; + reg17 |= 0x01; /* clock / 1 */ break; case SENSOR_OV7660: init = ov7660_sensor_param1; - if (sd->bridge == BRIDGE_SN9C120) { - if (mode) { /* 320x240 - 160x120 */ - reg17 = 0xa2; - reg1 = 0x44; /* 48 Mhz, video trf eneble */ - } - } else { - reg17 = 0x22; - reg1 = 0x06; /* 24 Mhz, video trf eneble - * inverse power down */ - } break; case SENSOR_PO1030: init = po1030_sensor_param1; - reg17 = 0xa2; - reg1 = 0x44; break; case SENSOR_PO2030N: init = po2030n_sensor_param1; - reg1 = 0x46; - reg17 = 0xa2; break; case SENSOR_SOI768: init = soi768_sensor_param1; - reg1 = 0x44; - reg17 = 0xa2; break; case SENSOR_SP80708: init = sp80708_sensor_param1; - if (mode) { -/*?? reg1 = 0x04; * 320 clk 48Mhz */ - } else { - reg1 = 0x46; /* 640 clk 48Mz */ - reg17 = 0xa2; - } break; } @@ -2684,7 +2607,9 @@ static int sd_start(struct gspca_dev *gspca_dev) setjpegqual(gspca_dev); reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, reg1); + reg_w1(gspca_dev, 0x01, reg01); + sd->reg01 = reg01; + sd->reg17 = reg17; sethvflip(gspca_dev); setbrightness(gspca_dev); @@ -2706,41 +2631,64 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 }; static const u8 stopsoi768[] = { 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 }; - u8 data; - const u8 *sn9c1xx; + u8 reg01; + u8 reg17; - data = 0x0b; + reg01 = sd->reg01; + reg17 = sd->reg17 & ~SEN_CLK_EN; switch (sd->sensor) { + case SENSOR_ADCM1700: case SENSOR_GC0307: - data = 0x29; + case SENSOR_PO2030N: + case SENSOR_SP80708: + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); + reg01 &= ~(LED | V_TX_EN); + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */ break; case SENSOR_HV7131R: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); i2c_w8(gspca_dev, stophv7131); - data = 0x2b; break; case SENSOR_MI0360: case SENSOR_MI0360B: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); +/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */ i2c_w8(gspca_dev, stopmi0360); - data = 0x29; break; - case SENSOR_OV7648: - i2c_w8(gspca_dev, stopov7648); - /* fall thru */ case SENSOR_MT9V111: - case SENSOR_OV7630: + case SENSOR_OM6802: case SENSOR_PO1030: - data = 0x29; + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + break; + case SENSOR_OV7630: + case SENSOR_OV7648: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); + i2c_w8(gspca_dev, stopov7648); + break; + case SENSOR_OV7660: + reg01 &= ~V_TX_EN; + reg_w1(gspca_dev, 0x01, reg01); break; case SENSOR_SOI768: i2c_w8(gspca_dev, stopsoi768); - data = 0x29; break; } - sn9c1xx = sn_tb[sd->sensor]; - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]); - reg_w1(gspca_dev, 0x01, sn9c1xx[1]); - reg_w1(gspca_dev, 0x01, data); + + reg01 |= SCL_SEL_OD; + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= S_PWR_DN; /* sensor power down */ + reg_w1(gspca_dev, 0x01, reg01); + reg_w1(gspca_dev, 0x17, reg17); + reg01 &= ~SYS_SEL_48M; /* clock 24MHz */ + reg_w1(gspca_dev, 0x01, reg01); + reg01 |= LED; + reg_w1(gspca_dev, 0x01, reg01); /* Don't disable sensor clock as that disables the button on the cam */ /* reg_w1(gspca_dev, 0xf1, 0x01); */ } @@ -2954,14 +2902,18 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ #define BS(bridge, sensor) \ .driver_info = (BRIDGE_ ## bridge << 16) \ - | SENSOR_ ## sensor + | (SENSOR_ ## sensor << 8) +#define BSF(bridge, sensor, flags) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (flags) static const __devinitdata struct usb_device_id device_table[] = { #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)}, {USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)}, #endif - {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)}, - {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)}, + {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, PDN_INV)}, + {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, PDN_INV)}, {USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)}, {USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)}, diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 2be23bccd3c8..48d2c2419c13 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = { .open = meye_open, .release = meye_release, .mmap = meye_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .poll = meye_poll, }; @@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, msleep(1); mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK); - if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, - video_nr) < 0) { - v4l2_err(v4l2_dev, "video_register_device failed\n"); - goto outvideoreg; - } - mutex_init(&meye.lock); init_waitqueue_head(&meye.proc_list); meye.brightness = 32 << 10; @@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev, sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0); sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48); + if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, + video_nr) < 0) { + v4l2_err(v4l2_dev, "video_register_device failed\n"); + goto outvideoreg; + } + v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n", MEYE_DRIVER_VERSION); v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n", diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index 072bd2d1cfad..13565cba237d 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c @@ -807,8 +807,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd, if (common_flags & SOCAM_PCLK_SAMPLE_RISING) csicr1 |= CSICR1_REDGE; - if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) - csicr1 |= CSICR1_INV_PCLK; if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) csicr1 |= CSICR1_SOF_POL; if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 7129b50757db..7551907f8c28 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf, static const struct v4l2_file_operations pms_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = pms_read, }; diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 1b93207c89e8..2f500809f53d 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -522,6 +522,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); fimc->vid_cap.active_buf_cnt = 0; fimc->vid_cap.frame_count = 0; + fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc); set_bit(ST_CAPT_PEND, &fimc->state); ret = videobuf_streamon(&fimc->vid_cap.vbq); @@ -652,6 +653,50 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv, return ret; } +static int fimc_cap_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cr) +{ + struct fimc_frame *f; + struct fimc_ctx *ctx = fh; + struct fimc_dev *fimc = ctx->fimc_dev; + + if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + f = &ctx->s_frame; + cr->bounds.left = 0; + cr->bounds.top = 0; + cr->bounds.width = f->o_width; + cr->bounds.height = f->o_height; + cr->defrect = cr->bounds; + + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) +{ + struct fimc_frame *f; + struct fimc_ctx *ctx = file->private_data; + struct fimc_dev *fimc = ctx->fimc_dev; + + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + f = &ctx->s_frame; + cr->c.left = f->offs_h; + cr->c.top = f->offs_v; + cr->c.width = f->width; + cr->c.height = f->height; + + mutex_unlock(&fimc->lock); + return 0; +} + static int fimc_cap_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) { @@ -716,9 +761,9 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_g_ctrl = fimc_vidioc_g_ctrl, .vidioc_s_ctrl = fimc_cap_s_ctrl, - .vidioc_g_crop = fimc_vidioc_g_crop, + .vidioc_g_crop = fimc_cap_g_crop, .vidioc_s_crop = fimc_cap_s_crop, - .vidioc_cropcap = fimc_vidioc_cropcap, + .vidioc_cropcap = fimc_cap_cropcap, .vidioc_enum_input = fimc_cap_enum_input, .vidioc_s_input = fimc_cap_s_input, @@ -785,7 +830,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops, vid_cap->v4l2_dev.dev, &fimc->irqlock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, - sizeof(struct fimc_vid_buffer), (void *)ctx); + sizeof(struct fimc_vid_buffer), (void *)ctx, NULL); ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret) { diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 2e7c547894b6..bb99f2d805d3 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -50,8 +50,8 @@ static struct fimc_fmt fimc_formats[] = { .planes_cnt = 1, .flags = FMT_FLAGS_M2M, }, { - .name = "XRGB-8-8-8-8, 24 bpp", - .fourcc = V4L2_PIX_FMT_RGB24, + .name = "XRGB-8-8-8-8, 32 bpp", + .fourcc = V4L2_PIX_FMT_RGB32, .depth = 32, .color = S5P_FIMC_RGB888, .buff_cnt = 1, @@ -983,6 +983,7 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, { struct fimc_ctx *ctx = priv; struct v4l2_queryctrl *c; + int ret = -EINVAL; c = get_ctrl(qc->id); if (c) { @@ -990,10 +991,14 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, return 0; } - if (ctx->state & FIMC_CTX_CAP) - return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, + if (ctx->state & FIMC_CTX_CAP) { + if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) + return -ERESTARTSYS; + ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, core, queryctrl, qc); - return -EINVAL; + mutex_unlock(&ctx->fimc_dev->lock); + } + return ret; } int fimc_vidioc_g_ctrl(struct file *file, void *priv, @@ -1115,7 +1120,7 @@ static int fimc_m2m_s_ctrl(struct file *file, void *priv, return 0; } -int fimc_vidioc_cropcap(struct file *file, void *fh, +static int fimc_m2m_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cr) { struct fimc_frame *frame; @@ -1139,7 +1144,7 @@ int fimc_vidioc_cropcap(struct file *file, void *fh, return 0; } -int fimc_vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) +static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) { struct fimc_frame *frame; struct fimc_ctx *ctx = file->private_data; @@ -1167,22 +1172,22 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) struct fimc_frame *f; u32 min_size, halign; - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? - &ctx->s_frame : &ctx->d_frame; - if (cr->c.top < 0 || cr->c.left < 0) { v4l2_err(&fimc->m2m.v4l2_dev, "doesn't support negative values for top & left\n"); return -EINVAL; } - f = ctx_get_frame(ctx, cr->type); - if (IS_ERR(f)) - return PTR_ERR(f); + if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame; + else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + ctx->state & FIMC_CTX_M2M) + f = &ctx->s_frame; + else + return -EINVAL; - min_size = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - ? fimc->variant->min_inp_pixsize - : fimc->variant->min_out_pixsize; + min_size = (f == &ctx->s_frame) ? + fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; if (ctx->state & FIMC_CTX_M2M) { if (fimc->id == 1 && fimc->variant->pix_hoff) @@ -1233,6 +1238,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? &ctx->s_frame : &ctx->d_frame; + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + spin_lock_irqsave(&ctx->slock, flags); if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) { /* Check to see if scaling ratio is within supported range */ @@ -1241,9 +1249,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) else ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); if (ret) { - spin_unlock_irqrestore(&ctx->slock, flags); v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); - return -EINVAL; + ret = -EINVAL; + goto scr_unlock; } } ctx->state |= FIMC_PARAMS; @@ -1253,7 +1261,9 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) f->width = cr->c.width; f->height = cr->c.height; +scr_unlock: spin_unlock_irqrestore(&ctx->slock, flags); + mutex_unlock(&fimc->lock); return 0; } @@ -1285,9 +1295,9 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_g_ctrl = fimc_vidioc_g_ctrl, .vidioc_s_ctrl = fimc_m2m_s_ctrl, - .vidioc_g_crop = fimc_vidioc_g_crop, + .vidioc_g_crop = fimc_m2m_g_crop, .vidioc_s_crop = fimc_m2m_s_crop, - .vidioc_cropcap = fimc_vidioc_cropcap + .vidioc_cropcap = fimc_m2m_cropcap }; @@ -1396,7 +1406,7 @@ static const struct v4l2_file_operations fimc_m2m_fops = { .open = fimc_m2m_open, .release = fimc_m2m_release, .poll = fimc_m2m_poll, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = fimc_m2m_mmap, }; @@ -1736,6 +1746,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, + .has_cistatus2 = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, @@ -1745,6 +1756,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .pix_hoff = 1, + .has_cistatus2 = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 3e1078516560..4f047d35f8ad 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -13,13 +13,15 @@ /*#define DEBUG*/ +#include <linux/sched.h> #include <linux/types.h> +#include <linux/videodev2.h> #include <media/videobuf-core.h> #include <media/v4l2-device.h> #include <media/v4l2-mem2mem.h> #include <media/v4l2-mediabus.h> #include <media/s3c_fimc.h> -#include <linux/videodev2.h> + #include "regs-fimc.h" #define err(fmt, args...) \ @@ -369,6 +371,7 @@ struct fimc_pix_limit { * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes * @has_inp_rot: set if has input rotator * @has_out_rot: set if has output rotator + * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision * @pix_limit: pixel size constraints for the scaler * @min_inp_pixsize: minimum input pixel size * @min_out_pixsize: minimum output pixel size @@ -379,6 +382,7 @@ struct samsung_fimc_variant { unsigned int pix_hoff:1; unsigned int has_inp_rot:1; unsigned int has_out_rot:1; + unsigned int has_cistatus2:1; struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; @@ -554,11 +558,19 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, return frame; } +/* Return an index to the buffer actually being written. */ static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev) { - u32 reg = readl(dev->regs + S5P_CISTATUS); - return (reg & S5P_CISTATUS_FRAMECNT_MASK) >> - S5P_CISTATUS_FRAMECNT_SHIFT; + u32 reg; + + if (dev->variant->has_cistatus2) { + reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F; + return reg > 0 ? --reg : reg; + } else { + reg = readl(dev->regs + S5P_CISTATUS); + return (reg & S5P_CISTATUS_FRAMECNT_MASK) >> + S5P_CISTATUS_FRAMECNT_SHIFT; + } } /* -----------------------------------------------------*/ @@ -594,10 +606,6 @@ int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f); int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f); -int fimc_vidioc_g_crop(struct file *file, void *fh, - struct v4l2_crop *cr); -int fimc_vidioc_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cr); int fimc_vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc); int fimc_vidioc_g_ctrl(struct file *file, void *priv, diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index a57daedb5b5c..57e33f84fcfa 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -165,6 +165,9 @@ #define S5P_CISTATUS_VVALID_A (1 << 15) #define S5P_CISTATUS_VVALID_B (1 << 14) +/* Indexes to the last and the currently processed buffer. */ +#define S5P_CISTATUS2 0x68 + /* Image capture control */ #define S5P_CIIMGCPT 0xc0 #define S5P_CIIMGCPT_IMGCPTEN (1 << 31) diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 5c209afb0ac8..2486520582f2 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -1980,7 +1980,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) * we complete the completion. */ - if (!csi2->driver || !csi2->driver->owner) { + if (!csi2->driver) { complete(&wait.completion); /* Either too late, or probing failed */ bus_unregister_notifier(&platform_bus_type, &wait.notifier); diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c index 4e5a8cf76ded..07cf0c6c7c1f 100644 --- a/drivers/media/video/sh_vou.c +++ b/drivers/media/video/sh_vou.c @@ -75,6 +75,7 @@ struct sh_vou_device { int pix_idx; struct videobuf_buffer *active; enum sh_vou_status status; + struct mutex fop_lock; }; struct sh_vou_file { @@ -235,7 +236,7 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) vb->state = VIDEOBUF_NEEDS_INIT; } -/* Locking: caller holds vq->vb_lock mutex */ +/* Locking: caller holds fop_lock mutex */ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { @@ -257,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, return 0; } -/* Locking: caller holds vq->vb_lock mutex */ +/* Locking: caller holds fop_lock mutex */ static int sh_vou_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) @@ -306,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq, return 0; } -/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */ +/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ static void sh_vou_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -1190,7 +1191,7 @@ static int sh_vou_open(struct file *file) V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), vdev, - NULL); + &vou_dev->fop_lock); return 0; } @@ -1292,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = { .owner = THIS_MODULE, .open = sh_vou_open, .release = sh_vou_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = sh_vou_mmap, .poll = sh_vou_poll, }; @@ -1331,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) INIT_LIST_HEAD(&vou_dev->queue); spin_lock_init(&vou_dev->lock); + mutex_init(&vou_dev->fop_lock); atomic_set(&vou_dev->use_count, 0); vou_dev->pdata = vou_pdata; vou_dev->status = SH_VOU_IDLE; @@ -1388,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev) vdev->tvnorms |= V4L2_STD_PAL; vdev->v4l2_dev = &vou_dev->v4l2_dev; vdev->release = video_device_release; + vdev->lock = &vou_dev->fop_lock; vou_dev->vdev = vdev; video_set_drvdata(vdev, vou_dev); diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 28e19daadec9..f49fbfb7dc13 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -3238,7 +3238,7 @@ static const struct v4l2_file_operations sn9c102_fops = { .owner = THIS_MODULE, .open = sn9c102_open, .release = sn9c102_release, - .ioctl = sn9c102_ioctl, + .unlocked_ioctl = sn9c102_ioctl, .read = sn9c102_read, .poll = sn9c102_poll, .mmap = sn9c102_mmap, diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 335120c2021b..052bd6dfa5a7 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -405,13 +405,13 @@ static int soc_camera_open(struct file *file) ret = soc_camera_set_fmt(icd, &f); if (ret < 0) goto esfmt; + + ici->ops->init_videobuf(&icd->vb_vidq, icd); } file->private_data = icd; dev_dbg(&icd->dev, "camera device open\n"); - ici->ops->init_videobuf(&icd->vb_vidq, icd); - mutex_unlock(&icd->video_lock); return 0; diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f169f7736677..59f8a9ad3796 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -785,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, } } -struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, +static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, __u32 v4l2_id, struct uvc_control_mapping **mapping) { struct uvc_control *ctrl = NULL; @@ -944,6 +944,52 @@ done: return ret; } +/* + * Mapping V4L2 controls to UVC controls can be straighforward if done well. + * Most of the UVC controls exist in V4L2, and can be mapped directly. Some + * must be grouped (for instance the Red Balance, Blue Balance and Do White + * Balance V4L2 controls use the White Balance Component UVC control) or + * otherwise translated. The approach we take here is to use a translation + * table for the controls that can be mapped directly, and handle the others + * manually. + */ +int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu) +{ + struct uvc_menu_info *menu_info; + struct uvc_control_mapping *mapping; + struct uvc_control *ctrl; + u32 index = query_menu->index; + u32 id = query_menu->id; + int ret; + + memset(query_menu, 0, sizeof(*query_menu)); + query_menu->id = id; + query_menu->index = index; + + ret = mutex_lock_interruptible(&chain->ctrl_mutex); + if (ret < 0) + return -ERESTARTSYS; + + ctrl = uvc_find_control(chain, query_menu->id, &mapping); + if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { + ret = -EINVAL; + goto done; + } + + if (query_menu->index >= mapping->menu_count) { + ret = -EINVAL; + goto done; + } + + menu_info = &mapping->menu_info[query_menu->index]; + strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); + +done: + mutex_unlock(&chain->ctrl_mutex); + return ret; +} + /* -------------------------------------------------------------------------- * Control transactions diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index ed6d5449741c..f14581bd707f 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -90,6 +90,39 @@ void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, } /* + * Free the video buffers. + * + * This function must be called with the queue lock held. + */ +static int __uvc_free_buffers(struct uvc_video_queue *queue) +{ + unsigned int i; + + for (i = 0; i < queue->count; ++i) { + if (queue->buffer[i].vma_use_count != 0) + return -EBUSY; + } + + if (queue->count) { + vfree(queue->mem); + queue->count = 0; + } + + return 0; +} + +int uvc_free_buffers(struct uvc_video_queue *queue) +{ + int ret; + + mutex_lock(&queue->mutex); + ret = __uvc_free_buffers(queue); + mutex_unlock(&queue->mutex); + + return ret; +} + +/* * Allocate the video buffers. * * Pages are reserved to make sure they will not be swapped, as they will be @@ -110,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, mutex_lock(&queue->mutex); - if ((ret = uvc_free_buffers(queue)) < 0) + if ((ret = __uvc_free_buffers(queue)) < 0) goto done; /* Bail out if no buffers should be allocated. */ @@ -152,28 +185,6 @@ done: } /* - * Free the video buffers. - * - * This function must be called with the queue lock held. - */ -int uvc_free_buffers(struct uvc_video_queue *queue) -{ - unsigned int i; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } - - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } - - return 0; -} - -/* * Check if buffers have been allocated. */ int uvc_queue_allocated(struct uvc_video_queue *queue) @@ -369,6 +380,82 @@ done: } /* + * VMA operations. + */ +static void uvc_vm_open(struct vm_area_struct *vma) +{ + struct uvc_buffer *buffer = vma->vm_private_data; + buffer->vma_use_count++; +} + +static void uvc_vm_close(struct vm_area_struct *vma) +{ + struct uvc_buffer *buffer = vma->vm_private_data; + buffer->vma_use_count--; +} + +static const struct vm_operations_struct uvc_vm_ops = { + .open = uvc_vm_open, + .close = uvc_vm_close, +}; + +/* + * Memory-map a video buffer. + * + * This function implements video buffers memory mapping and is intended to be + * used by the device mmap handler. + */ +int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) +{ + struct uvc_buffer *uninitialized_var(buffer); + struct page *page; + unsigned long addr, start, size; + unsigned int i; + int ret = 0; + + start = vma->vm_start; + size = vma->vm_end - vma->vm_start; + + mutex_lock(&queue->mutex); + + for (i = 0; i < queue->count; ++i) { + buffer = &queue->buffer[i]; + if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + + if (i == queue->count || size != queue->buf_size) { + ret = -EINVAL; + goto done; + } + + /* + * VM_IO marks the area as being an mmaped region for I/O to a + * device. It also prevents the region from being core dumped. + */ + vma->vm_flags |= VM_IO; + + addr = (unsigned long)queue->mem + buffer->buf.m.offset; + while (size > 0) { + page = vmalloc_to_page((void *)addr); + if ((ret = vm_insert_page(vma, start, page)) < 0) + goto done; + + start += PAGE_SIZE; + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + vma->vm_ops = &uvc_vm_ops; + vma->vm_private_data = buffer; + uvc_vm_open(vma); + +done: + mutex_unlock(&queue->mutex); + return ret; +} + +/* * Poll the video queue. * * This function implements video queue polling and is intended to be used by diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 6d15de9b5204..8cf61e8a634f 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -101,40 +101,6 @@ done: */ /* - * Mapping V4L2 controls to UVC controls can be straighforward if done well. - * Most of the UVC controls exist in V4L2, and can be mapped directly. Some - * must be grouped (for instance the Red Balance, Blue Balance and Do White - * Balance V4L2 controls use the White Balance Component UVC control) or - * otherwise translated. The approach we take here is to use a translation - * table for the controls that can be mapped directly, and handle the others - * manually. - */ -static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, - struct v4l2_querymenu *query_menu) -{ - struct uvc_menu_info *menu_info; - struct uvc_control_mapping *mapping; - struct uvc_control *ctrl; - u32 index = query_menu->index; - u32 id = query_menu->id; - - ctrl = uvc_find_control(chain, query_menu->id, &mapping); - if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) - return -EINVAL; - - if (query_menu->index >= mapping->menu_count) - return -EINVAL; - - memset(query_menu, 0, sizeof(*query_menu)); - query_menu->id = id; - query_menu->index = index; - - menu_info = &mapping->menu_info[query_menu->index]; - strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name); - return 0; -} - -/* * Find the frame interval closest to the requested frame interval for the * given frame format and size. This should be done by the device as part of * the Video Probe and Commit negotiation, but some hardware don't implement @@ -260,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ + mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); + mutex_unlock(&stream->mutex); if (ret < 0) goto done; @@ -289,14 +257,21 @@ done: static int uvc_v4l2_get_format(struct uvc_streaming *stream, struct v4l2_format *fmt) { - struct uvc_format *format = stream->cur_format; - struct uvc_frame *frame = stream->cur_frame; + struct uvc_format *format; + struct uvc_frame *frame; + int ret = 0; if (fmt->type != stream->type) return -EINVAL; - if (format == NULL || frame == NULL) - return -EINVAL; + mutex_lock(&stream->mutex); + format = stream->cur_format; + frame = stream->cur_frame; + + if (format == NULL || frame == NULL) { + ret = -EINVAL; + goto done; + } fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -307,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, fmt->fmt.pix.colorspace = format->colorspace; fmt->fmt.pix.priv = 0; - return 0; +done: + mutex_unlock(&stream->mutex); + return ret; } static int uvc_v4l2_set_format(struct uvc_streaming *stream, @@ -321,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream, if (fmt->type != stream->type) return -EINVAL; - if (uvc_queue_allocated(&stream->queue)) - return -EBUSY; - ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); if (ret < 0) return ret; + mutex_lock(&stream->mutex); + + if (uvc_queue_allocated(&stream->queue)) { + ret = -EBUSY; + goto done; + } + memcpy(&stream->ctrl, &probe, sizeof probe); stream->cur_format = format; stream->cur_frame = frame; - return 0; +done: + mutex_unlock(&stream->mutex); + return ret; } static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, @@ -343,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, if (parm->type != stream->type) return -EINVAL; + mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; + mutex_unlock(&stream->mutex); + denominator = 10000000; uvc_simplify_fraction(&numerator, &denominator, 8, 333); @@ -370,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { - struct uvc_frame *frame = stream->cur_frame; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; uint32_t interval; @@ -379,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, if (parm->type != stream->type) return -EINVAL; - if (uvc_queue_streaming(&stream->queue)) - return -EBUSY; - if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) timeperframe = parm->parm.capture.timeperframe; else timeperframe = parm->parm.output.timeperframe; - memcpy(&probe, &stream->ctrl, sizeof probe); interval = uvc_fraction_to_interval(timeperframe.numerator, timeperframe.denominator); - uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", timeperframe.numerator, timeperframe.denominator, interval); - probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); + + mutex_lock(&stream->mutex); + + if (uvc_queue_streaming(&stream->queue)) { + mutex_unlock(&stream->mutex); + return -EBUSY; + } + + memcpy(&probe, &stream->ctrl, sizeof probe); + probe.dwFrameInterval = + uvc_try_frame_interval(stream->cur_frame, interval); /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&stream->mutex); return ret; + } memcpy(&stream->ctrl, &probe, sizeof probe); + mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -528,11 +521,9 @@ static int uvc_v4l2_release(struct file *file) if (uvc_has_privileges(handle)) { uvc_video_enable(stream, 0); - mutex_lock(&stream->queue.mutex); if (uvc_free_buffers(&stream->queue) < 0) uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " "free buffers.\n"); - mutex_unlock(&stream->queue.mutex); } /* Release the file handle. */ @@ -624,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_QUERYMENU: - return uvc_v4l2_query_menu(chain, arg); + return uvc_query_v4l2_menu(chain, arg); case VIDIOC_G_EXT_CTRLS: { @@ -905,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_CROPCAP: { struct v4l2_cropcap *ccap = arg; - struct uvc_frame *frame = stream->cur_frame; if (ccap->type != stream->type) return -EINVAL; ccap->bounds.left = 0; ccap->bounds.top = 0; - ccap->bounds.width = frame->wWidth; - ccap->bounds.height = frame->wHeight; + + mutex_lock(&stream->mutex); + ccap->bounds.width = stream->cur_frame->wWidth; + ccap->bounds.height = stream->cur_frame->wHeight; + mutex_unlock(&stream->mutex); ccap->defrect = ccap->bounds; @@ -930,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *rb = arg; - unsigned int bufsize = - stream->ctrl.dwMaxVideoFrameSize; if (rb->type != stream->type || rb->memory != V4L2_MEMORY_MMAP) @@ -940,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize); + mutex_lock(&stream->mutex); + ret = uvc_alloc_buffers(&stream->queue, rb->count, + stream->ctrl.dwMaxVideoFrameSize); + mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -988,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (!uvc_has_privileges(handle)) return -EBUSY; + mutex_lock(&stream->mutex); ret = uvc_video_enable(stream, 1); + mutex_unlock(&stream->mutex); if (ret < 0) return ret; break; @@ -1068,79 +1064,14 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data, return -EINVAL; } -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; -} - -static const struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { struct uvc_fh *handle = file->private_data; struct uvc_streaming *stream = handle->stream; - struct uvc_video_queue *queue = &stream->queue; - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n"); - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; - - mutex_lock(&queue->mutex); - - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || size != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); - -done: - mutex_unlock(&queue->mutex); - return ret; + return uvc_queue_mmap(&stream->queue, vma); } static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) @@ -1157,7 +1088,7 @@ const struct v4l2_file_operations uvc_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, - .ioctl = uvc_v4l2_ioctl, + .unlocked_ioctl = uvc_v4l2_ioctl, .read = uvc_v4l2_read, .mmap = uvc_v4l2_mmap, .poll = uvc_v4l2_poll, diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 5555f0102838..5673d673504b 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -293,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream, unsigned int i; int ret; - mutex_lock(&stream->mutex); - /* Perform probing. The device should adjust the requested values * according to its capabilities. However, some devices, namely the * first generation UVC Logitech webcams, don't implement the Video @@ -346,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream, } done: - mutex_unlock(&stream->mutex); return ret; } diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index d97cf6d6a4f9..45f01e7e13d2 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -436,7 +436,9 @@ struct uvc_streaming { struct uvc_streaming_control ctrl; struct uvc_format *cur_format; struct uvc_frame *cur_frame; - + /* Protect access to ctrl, cur_format, cur_frame and hardware video + * probe control. + */ struct mutex mutex; unsigned int frozen : 1; @@ -574,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable); extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); +extern int uvc_queue_mmap(struct uvc_video_queue *queue, + struct vm_area_struct *vma); extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, poll_table *wait); extern int uvc_queue_allocated(struct uvc_video_queue *queue); @@ -606,10 +610,10 @@ extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); /* Controls */ -extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, - __u32 v4l2_id, struct uvc_control_mapping **mapping); extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct v4l2_queryctrl *v4l2_ctrl); +extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, + struct v4l2_querymenu *query_menu); extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain, const struct uvc_control_mapping *mapping); diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 03f7f4670e9b..359e23290a7e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -186,12 +186,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { struct video_device *vdev = video_devdata(filp); - int ret = -EIO; + int ret = -ENODEV; if (!vdev->fops->read) return -EINVAL; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->read(filp, buf, sz, off); if (vdev->lock) @@ -203,12 +203,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, size_t sz, loff_t *off) { struct video_device *vdev = video_devdata(filp); - int ret = -EIO; + int ret = -ENODEV; if (!vdev->fops->write) return -EINVAL; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->write(filp, buf, sz, off); if (vdev->lock) @@ -219,10 +219,10 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) { struct video_device *vdev = video_devdata(filp); - int ret = DEFAULT_POLLMASK; + int ret = POLLERR | POLLHUP; if (!vdev->fops->poll) - return ret; + return DEFAULT_POLLMASK; if (vdev->lock) mutex_lock(vdev->lock); if (video_is_registered(vdev)) @@ -238,20 +238,45 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) int ret = -ENODEV; if (vdev->fops->unlocked_ioctl) { - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); if (vdev->lock) mutex_unlock(vdev->lock); } else if (vdev->fops->ioctl) { - /* TODO: convert all drivers to unlocked_ioctl */ + /* This code path is a replacement for the BKL. It is a major + * hack but it will have to do for those drivers that are not + * yet converted to use unlocked_ioctl. + * + * There are two options: if the driver implements struct + * v4l2_device, then the lock defined there is used to + * serialize the ioctls. Otherwise the v4l2 core lock defined + * below is used. This lock is really bad since it serializes + * completely independent devices. + * + * Both variants suffer from the same problem: if the driver + * sleeps, then it blocks all ioctls since the lock is still + * held. This is very common for VIDIOC_DQBUF since that + * normally waits for a frame to arrive. As a result any other + * ioctl calls will proceed very, very slowly since each call + * will have to wait for the VIDIOC_QBUF to finish. Things that + * should take 0.01s may now take 10-20 seconds. + * + * The workaround is to *not* take the lock for VIDIOC_DQBUF. + * This actually works OK for videobuf-based drivers, since + * videobuf will take its own internal lock. + */ static DEFINE_MUTEX(v4l2_ioctl_mutex); + struct mutex *m = vdev->v4l2_dev ? + &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex; - mutex_lock(&v4l2_ioctl_mutex); + if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->ioctl(filp, cmd, arg); - mutex_unlock(&v4l2_ioctl_mutex); + if (cmd != VIDIOC_DQBUF) + mutex_unlock(m); } else ret = -ENOTTY; @@ -265,8 +290,8 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) if (!vdev->fops->mmap) return ret; - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) + return -ERESTARTSYS; if (video_is_registered(vdev)) ret = vdev->fops->mmap(filp, vm); if (vdev->lock) @@ -284,7 +309,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) mutex_lock(&videodev_lock); vdev = video_devdata(filp); /* return ENODEV if the video device has already been removed. */ - if (vdev == NULL) { + if (vdev == NULL || !video_is_registered(vdev)) { mutex_unlock(&videodev_lock); return -ENODEV; } @@ -292,8 +317,10 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); if (vdev->fops->open) { - if (vdev->lock) - mutex_lock(vdev->lock); + if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { + ret = -ERESTARTSYS; + goto err; + } if (video_is_registered(vdev)) ret = vdev->fops->open(filp); else @@ -302,6 +329,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } +err: /* decrease the refcount in case of an error */ if (ret) video_put(vdev); @@ -596,7 +624,12 @@ void video_unregister_device(struct video_device *vdev) if (!vdev || !video_is_registered(vdev)) return; + mutex_lock(&videodev_lock); + /* This must be in a critical section to prevent a race with v4l2_open. + * Once this bit has been cleared video_get may never be called again. + */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); + mutex_unlock(&videodev_lock); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 0b08f96b74a5..7fe6f92af480 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -35,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); + mutex_init(&v4l2_dev->ioctl_lock); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c index 635420d8d84a..019ee206cbee 100644 --- a/drivers/media/video/w9966.c +++ b/drivers/media/video/w9966.c @@ -815,7 +815,7 @@ out: static const struct v4l2_file_operations w9966_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .read = w9966_v4l_read, }; diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 135525649086..fe8ef6419f83 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -35,7 +35,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-ctrls.h> -#include <media/wm8775.h> MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -51,16 +50,10 @@ enum { TOT_REGS }; -#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */ -#define ALC_EN 0x100 /* R17: ALC enable */ - struct wm8775_state { struct v4l2_subdev sd; struct v4l2_ctrl_handler hdl; struct v4l2_ctrl *mute; - struct v4l2_ctrl *vol; - struct v4l2_ctrl *bal; - struct v4l2_ctrl *loud; u8 input; /* Last selected input (0-0xf) */ }; @@ -92,30 +85,6 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val) return -1; } -static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly) -{ - struct wm8775_state *state = to_state(sd); - u8 vol_l, vol_r; - int muted = 0 != state->mute->val; - u16 volume = (u16)state->vol->val; - u16 balance = (u16)state->bal->val; - - /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */ - vol_l = (min(65536 - balance, 32768) * volume) >> 23; - vol_r = (min(balance, (u16)32768) * volume) >> 23; - - /* Mute */ - if (muted || quietly) - wm8775_write(sd, R21, 0x0c0 | state->input); - - wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */ - wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */ - - /* Un-mute */ - if (!muted) - wm8775_write(sd, R21, state->input); -} - static int wm8775_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) { @@ -133,26 +102,25 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, state->input = input; if (!v4l2_ctrl_g_ctrl(state->mute)) return 0; - if (!v4l2_ctrl_g_ctrl(state->vol)) - return 0; - if (!v4l2_ctrl_g_ctrl(state->bal)) - return 0; - wm8775_set_audio(sd, 1); + wm8775_write(sd, R21, 0x0c0); + wm8775_write(sd, R14, 0x1d4); + wm8775_write(sd, R15, 0x1d4); + wm8775_write(sd, R21, 0x100 + state->input); return 0; } static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_sd(ctrl); + struct wm8775_state *state = to_state(sd); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - wm8775_set_audio(sd, 0); - return 0; - case V4L2_CID_AUDIO_LOUDNESS: - wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD); + wm8775_write(sd, R21, 0x0c0); + wm8775_write(sd, R14, 0x1d4); + wm8775_write(sd, R15, 0x1d4); + if (!ctrl->val) + wm8775_write(sd, R21, 0x100 + state->input); return 0; } return -EINVAL; @@ -176,7 +144,16 @@ static int wm8775_log_status(struct v4l2_subdev *sd) static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) { - wm8775_set_audio(sd, 0); + struct wm8775_state *state = to_state(sd); + + /* If I remove this, then it can happen that I have no + sound the first time I tune from static to a valid channel. + It's difficult to reproduce and is almost certainly related + to the zero cross detect circuit. */ + wm8775_write(sd, R21, 0x0c0); + wm8775_write(sd, R14, 0x1d4); + wm8775_write(sd, R15, 0x1d4); + wm8775_write(sd, R21, 0x100 + state->input); return 0; } @@ -226,7 +203,6 @@ static int wm8775_probe(struct i2c_client *client, { struct wm8775_state *state; struct v4l2_subdev *sd; - int err; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -240,21 +216,15 @@ static int wm8775_probe(struct i2c_client *client, return -ENOMEM; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &wm8775_ops); - sd->grp_id = WM8775_GID; /* subdev group id */ state->input = 2; - v4l2_ctrl_handler_init(&state->hdl, 4); + v4l2_ctrl_handler_init(&state->hdl, 1); state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/ - state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768); - state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, - V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1); sd->ctrl_handler = &state->hdl; - err = state->hdl.error; - if (err) { + if (state->hdl.error) { + int err = state->hdl.error; + v4l2_ctrl_handler_free(&state->hdl); kfree(state); return err; @@ -266,25 +236,29 @@ static int wm8775_probe(struct i2c_client *client, wm8775_write(sd, R23, 0x000); /* Disable zero cross detect timeout */ wm8775_write(sd, R7, 0x000); - /* HPF enable, I2S mode, 24-bit */ - wm8775_write(sd, R11, 0x022); + /* Left justified, 24-bit mode */ + wm8775_write(sd, R11, 0x021); /* Master mode, clock ratio 256fs */ wm8775_write(sd, R12, 0x102); /* Powered up */ wm8775_write(sd, R13, 0x000); - /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */ - wm8775_write(sd, R16, 0x1bb); - /* Set ALC mode and hold time */ - wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(sd, R14, 0x1d4); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(sd, R15, 0x1d4); + /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ + wm8775_write(sd, R16, 0x1bf); + /* Enable gain control, use zero cross detection, + ALC hold time 42.6 ms */ + wm8775_write(sd, R17, 0x185); /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ wm8775_write(sd, R18, 0x0a2); /* Enable noise gate, threshold -72dBfs */ wm8775_write(sd, R19, 0x005); - /* Transient window 4ms, ALC min gain -5dB */ - wm8775_write(sd, R20, 0x0fb); - - wm8775_set_audio(sd, 1); /* set volume/mute/mux */ - + /* Transient window 4ms, lower PGA gain limit -1dB */ + wm8775_write(sd, R20, 0x07a); + /* LRBOTH = 1, use input 2. */ + wm8775_write(sd, R21, 0x102); return 0; } diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index dbe1c93c1af3..d9640a623ff4 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -303,7 +303,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev) continue; do { - int bit = __ffs(status); + int bit = __ffs(value); int line = i * 8 + bit; handle_nested_irq(ab8500->irq_base + line); diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 7d2563fc15c6..76cadcf3b1fe 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1455,7 +1455,11 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret); goto err; } - if (ret != 0x6204) { + switch (ret) { + case 0x6204: + case 0x6246: + break; + default: dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret); ret = -EINVAL; goto err; @@ -1620,7 +1624,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8325: ret = mfd_add_devices(wm831x->dev, -1, wm8320_devs, ARRAY_SIZE(wm8320_devs), - NULL, 0); + NULL, wm831x->irq_base); break; default: diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 31ae07a36576..57dcf8fa774a 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1773,6 +1773,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, case PM_POST_SUSPEND: case PM_POST_HIBERNATION: + case PM_POST_RESTORE: spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c index 591ab540b407..d3e6a962f423 100644 --- a/drivers/mmc/host/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -69,6 +69,7 @@ #include <linux/highmem.h> #include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> #include <asm/io.h> #include <asm/irq.h> @@ -493,10 +494,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command else if (data->flags & MMC_DATA_WRITE) cmdr |= AT91_MCI_TRCMD_START; - if (data->flags & MMC_DATA_STREAM) - cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->blocks > 1) - cmdr |= AT91_MCI_TRTYP_MULTIPLE; + if (cmd->opcode == SD_IO_RW_EXTENDED) { + cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; + } else { + if (data->flags & MMC_DATA_STREAM) + cmdr |= AT91_MCI_TRTYP_STREAM; + if (data->blocks > 1) + cmdr |= AT91_MCI_TRTYP_MULTIPLE; + } } else { block_length = 0; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 301351a5d838..ad2a7a032cdf 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -26,6 +26,7 @@ #include <linux/stat.h> #include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> #include <mach/atmel-mci.h> #include <linux/atmel-mci.h> @@ -532,12 +533,17 @@ static u32 atmci_prepare_command(struct mmc_host *mmc, data = cmd->data; if (data) { cmdr |= MCI_CMDR_START_XFER; - if (data->flags & MMC_DATA_STREAM) - cmdr |= MCI_CMDR_STREAM; - else if (data->blocks > 1) - cmdr |= MCI_CMDR_MULTI_BLOCK; - else - cmdr |= MCI_CMDR_BLOCK; + + if (cmd->opcode == SD_IO_RW_EXTENDED) { + cmdr |= MCI_CMDR_SDIO_BLOCK; + } else { + if (data->flags & MMC_DATA_STREAM) + cmdr |= MCI_CMDR_STREAM; + else if (data->blocks > 1) + cmdr |= MCI_CMDR_MULTI_BLOCK; + else + cmdr |= MCI_CMDR_BLOCK; + } if (data->flags & MMC_DATA_READ) cmdr |= MCI_CMDR_TRDIR_READ; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87b4fc6c98c2..563022825667 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -19,6 +19,7 @@ #include <linux/highmem.h> #include <linux/log2.h> #include <linux/mmc/host.h> +#include <linux/mmc/card.h> #include <linux/amba/bus.h> #include <linux/clk.h> #include <linux/scatterlist.h> @@ -45,6 +46,12 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) + * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware + * and will not work at all. + * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when + * using DMA. + * @sdio: variant supports SDIO + * @st_clkdiv: true if using a ST-specific clock divider algorithm */ struct variant_data { unsigned int clkreg; @@ -52,6 +59,10 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; + bool broken_blockend; + bool broken_blockend_dma; + bool sdio; + bool st_clkdiv; }; static struct variant_data variant_arm = { @@ -65,6 +76,8 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, + .broken_blockend_dma = true, + .sdio = true, }; static struct variant_data variant_ux500 = { @@ -73,7 +86,11 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, + .broken_blockend = true, + .sdio = true, + .st_clkdiv = true, }; + /* * This must be called with host->lock held */ @@ -86,7 +103,22 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (desired >= host->mclk) { clk = MCI_CLK_BYPASS; host->cclk = host->mclk; + } else if (variant->st_clkdiv) { + /* + * DB8500 TRM says f = mclk / (clkdiv + 2) + * => clkdiv = (mclk / f) - 2 + * Round the divider up so we don't exceed the max + * frequency + */ + clk = DIV_ROUND_UP(host->mclk, desired) - 2; + if (clk >= 256) + clk = 255; + host->cclk = host->mclk / (clk + 2); } else { + /* + * PL180 TRM says f = mclk / (2 * (clkdiv + 1)) + * => clkdiv = mclk / (2 * f) - 1 + */ clk = host->mclk / (2 * desired) - 1; if (clk >= 256) clk = 255; @@ -129,10 +161,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) spin_lock(&host->lock); } +static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +{ + void __iomem *base = host->base; + + if (host->singleirq) { + unsigned int mask0 = readl(base + MMCIMASK0); + + mask0 &= ~MCI_IRQ1MASK; + mask0 |= mask; + + writel(mask0, base + MMCIMASK0); + } + + writel(mask, base + MMCIMASK1); +} + static void mmci_stop_data(struct mmci_host *host) { writel(0, host->base + MMCIDATACTRL); - writel(0, host->base + MMCIMASK1); + mmci_set_mask1(host, 0); host->data = NULL; } @@ -162,6 +210,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; + host->blockend = false; + host->dataend = false; mmci_init_sg(host, data); @@ -196,9 +246,14 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } + /* The ST Micro variants has a special bit to enable SDIO */ + if (variant->sdio && host->mmc->card) + if (mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); - writel(irqmask, base + MMCIMASK1); + mmci_set_mask1(host, irqmask); } static void @@ -233,20 +288,9 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - if (status & MCI_DATABLOCKEND) { - host->data_xfered += data->blksz; -#ifdef CONFIG_ARCH_U300 - /* - * On the U300 some signal or other is - * badly routed so that a data write does - * not properly terminate with a MCI_DATAEND - * status flag. This quirk will make writes - * work again. - */ - if (data->flags & MMC_DATA_WRITE) - status |= MCI_DATAEND; -#endif - } + struct variant_data *variant = host->variant; + + /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) @@ -255,7 +299,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = -EIO; - status |= MCI_DATAEND; + + /* Force-complete the transaction */ + host->blockend = true; + host->dataend = true; /* * We hit an error condition. Ensure that any data @@ -273,9 +320,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, local_irq_restore(flags); } } - if (status & MCI_DATAEND) { + + /* + * On ARM variants in PIO mode, MCI_DATABLOCKEND + * is always sent first, and we increase the + * transfered number of bytes for that IRQ. Then + * MCI_DATAEND follows and we conclude the transaction. + * + * On the Ux500 single-IRQ variant MCI_DATABLOCKEND + * doesn't seem to immediately clear from the status, + * so we can't use it keep count when only one irq is + * used because the irq will hit for other reasons, and + * then the flag is still up. So we use the MCI_DATAEND + * IRQ at the end of the entire transfer because + * MCI_DATABLOCKEND is broken. + * + * In the U300, the IRQs can arrive out-of-order, + * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, + * so for this case we use the flags "blockend" and + * "dataend" to make sure both IRQs have arrived before + * concluding the transaction. (This does not apply + * to the Ux500 which doesn't fire MCI_DATABLOCKEND + * at all.) In DMA mode it suffers from the same problem + * as the Ux500. + */ + if (status & MCI_DATABLOCKEND) { + /* + * Just being a little over-cautious, we do not + * use this progressive update if the hardware blockend + * flag is unreliable: since it can stay high between + * IRQs it will corrupt the transfer counter. + */ + if (!variant->broken_blockend) + host->data_xfered += data->blksz; + host->blockend = true; + } + + if (status & MCI_DATAEND) + host->dataend = true; + + /* + * On variants with broken blockend we shall only wait for dataend, + * on others we must sync with the blockend signal since they can + * appear out-of-order. + */ + if (host->dataend && (host->blockend || variant->broken_blockend)) { mmci_stop_data(host); + /* Reset these flags */ + host->blockend = false; + host->dataend = false; + + /* + * Variants with broken blockend flags need to handle the + * end of the entire transfer here. + */ + if (variant->broken_blockend && !data->error) + host->data_xfered += data->blksz * data->blocks; + if (!data->stop) { mmci_request_end(host, data->mrq); } else { @@ -356,7 +458,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); - writesl(base + MMCIFIFO, ptr, count >> 2); + /* + * The ST Micro variant for SDIO transfer sizes + * less then 8 bytes should have clock H/W flow + * control disabled. + */ + if (variant->sdio && + mmc_card_sdio(host->mmc->card)) { + if (count < 8) + writel(readl(host->base + MMCICLOCK) & + ~variant->clkreg_enable, + host->base + MMCICLOCK); + else + writel(readl(host->base + MMCICLOCK) | + variant->clkreg_enable, + host->base + MMCICLOCK); + } + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc), and the FIFO only accept full 32-bit writes. + * So compensate by adding +3 on the count, a single + * byte become a 32bit write, 7 bytes will be two + * 32bit writes etc. + */ + writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); ptr += count; remain -= count; @@ -437,7 +564,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * "any data available" mode. */ if (status & MCI_RXACTIVE && host->size < variant->fifosize) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* * If we run out of data, disable the data IRQs; this @@ -446,7 +573,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * stops us racing with our data end IRQ. */ if (host->size == 0) { - writel(0, base + MMCIMASK1); + mmci_set_mask1(host, 0); writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); } @@ -469,6 +596,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) struct mmc_data *data; status = readl(host->base + MMCISTATUS); + + if (host->singleirq) { + if (status & readl(host->base + MMCIMASK1)) + mmci_pio_irq(irq, dev_id); + + status &= ~MCI_IRQ1MASK; + } + status &= readl(host->base + MMCIMASK0); writel(status, host->base + MMCICLEAR); @@ -635,6 +770,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; + unsigned int mask; int ret; /* must have platform data */ @@ -806,20 +942,30 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (ret) goto unmap; - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); - if (ret) - goto irq0_free; + if (dev->irq[1] == NO_IRQ) + host->singleirq = true; + else { + ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, + DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mask = MCI_IRQENABLE; + /* Don't use the datablockend flag if it's broken */ + if (variant->broken_blockend) + mask &= ~MCI_DATABLOCKEND; - amba_set_drvdata(dev, mmc); + writel(mask, host->base + MMCIMASK0); - mmc_add_host(mmc); + amba_set_drvdata(dev, mmc); - dev_info(&dev->dev, "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n", - mmc_hostname(mmc), amba_rev(dev), amba_config(dev), + dev_info(&dev->dev, "%s: PL%03x rev%u at 0x%08llx irq %d,%d\n", + mmc_hostname(mmc), amba_part(dev), amba_rev(dev), (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]); + mmc_add_host(mmc); + return 0; irq0_free: @@ -864,7 +1010,8 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); free_irq(dev->irq[0], host); - free_irq(dev->irq[1], host); + if (!host->singleirq) + free_irq(dev->irq[1], host); if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4ae887fc0189..df06f01aac89 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -139,6 +139,11 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) +/* These interrupts are directed to IRQ1 when two IRQ lines are available */ +#define MCI_IRQ1MASK \ + (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ + MCI_TXFIFOHALFEMPTYMASK) + #define NR_SG 16 struct clk; @@ -154,6 +159,7 @@ struct mmci_host { int gpio_cd; int gpio_wp; int gpio_cd_irq; + bool singleirq; unsigned int data_xfered; @@ -171,6 +177,9 @@ struct mmci_host { struct timer_list timer; unsigned int oldstat; + bool blockend; + bool dataend; + /* pio stuff */ struct sg_mapping_iter sg_miter; unsigned int size; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 09b099bfab2b..bdf11d89a499 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -702,6 +702,7 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter) adapter->wol = 0; + device_set_wakeup_enable(&pdev->dev, false); adapter->link_speed = SPEED_0; adapter->link_duplex = FULL_DUPLEX; adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE; @@ -2444,8 +2445,9 @@ static int atl1c_close(struct net_device *netdev) return 0; } -static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) +static int atl1c_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); struct atl1c_hw *hw = &adapter->hw; @@ -2454,7 +2456,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) u32 wol_ctrl_data = 0; u16 mii_intr_status_data = 0; u32 wufc = adapter->wol; - int retval = 0; atl1c_disable_l0s_l1(hw); if (netif_running(netdev)) { @@ -2462,9 +2463,6 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) atl1c_down(adapter); } netif_device_detach(netdev); - retval = pci_save_state(pdev); - if (retval) - return retval; if (wufc) if (atl1c_phy_power_saving(hw) != 0) @@ -2525,12 +2523,8 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data); AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); - /* pcie patch */ - device_set_wakeup_enable(&pdev->dev, 1); - AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET); - pci_prepare_to_sleep(pdev); } else { AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING); master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS; @@ -2540,25 +2534,17 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state) AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data); AT_WRITE_REG(hw, REG_WOL_CTRL, 0); hw->phy_configured = false; /* re-init PHY when resume */ - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); } - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } -static int atl1c_resume(struct pci_dev *pdev) +static int atl1c_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct atl1c_adapter *adapter = netdev_priv(netdev); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE | ATL1C_PCIE_PHY_RESET); @@ -2582,7 +2568,12 @@ static int atl1c_resume(struct pci_dev *pdev) static void atl1c_shutdown(struct pci_dev *pdev) { - atl1c_suspend(pdev, PMSG_SUSPEND); + struct net_device *netdev = pci_get_drvdata(pdev); + struct atl1c_adapter *adapter = netdev_priv(netdev); + + atl1c_suspend(&pdev->dev); + pci_wake_from_d3(pdev, adapter->wol); + pci_set_power_state(pdev, PCI_D3hot); } static const struct net_device_ops atl1c_netdev_ops = { @@ -2886,16 +2877,16 @@ static struct pci_error_handlers atl1c_err_handler = { .resume = atl1c_io_resume, }; +static SIMPLE_DEV_PM_OPS(atl1c_pm_ops, atl1c_suspend, atl1c_resume); + static struct pci_driver atl1c_driver = { .name = atl1c_driver_name, .id_table = atl1c_pci_tbl, .probe = atl1c_probe, .remove = __devexit_p(atl1c_remove), - /* Power Managment Hooks */ - .suspend = atl1c_suspend, - .resume = atl1c_resume, .shutdown = atl1c_shutdown, - .err_handler = &atl1c_err_handler + .err_handler = &atl1c_err_handler, + .driver.pm = &atl1c_pm_ops, }; /* diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 53363108994e..3acf5123a6ef 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -3504,6 +3504,8 @@ static int atl1_set_ringparam(struct net_device *netdev, struct atl1_rfd_ring rfd_old, rfd_new; struct atl1_rrd_ring rrd_old, rrd_new; struct atl1_ring_header rhdr_old, rhdr_new; + struct atl1_smb smb; + struct atl1_cmb cmb; int err; tpd_old = adapter->tpd_ring; @@ -3544,11 +3546,19 @@ static int atl1_set_ringparam(struct net_device *netdev, adapter->rrd_ring = rrd_old; adapter->tpd_ring = tpd_old; adapter->ring_header = rhdr_old; + /* + * Save SMB and CMB, since atl1_free_ring_resources + * will clear them. + */ + smb = adapter->smb; + cmb = adapter->cmb; atl1_free_ring_resources(adapter); adapter->rfd_ring = rfd_new; adapter->rrd_ring = rrd_new; adapter->tpd_ring = tpd_new; adapter->ring_header = rhdr_new; + adapter->smb = smb; + adapter->cmb = cmb; err = atl1_up(adapter); if (err) diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 4594a28b1f66..d64313b7090e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -234,7 +234,7 @@ struct be_adapter { u8 __iomem *db; /* Door Bell */ u8 __iomem *pcicfg; /* PCI config space */ - spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ + struct mutex mbox_lock; /* For serializing mbox cmds to BE card */ struct be_dma_mem mbox_mem; /* Mbox mem is adjusted to align to 16 bytes. The allocated addr * is stored for freeing purpose */ diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index e4465d222a7d..1c8c79c9d214 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -462,7 +462,8 @@ int be_cmd_fw_init(struct be_adapter *adapter) u8 *wrb; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = (u8 *)wrb_from_mbox(adapter); *wrb++ = 0xFF; @@ -476,7 +477,7 @@ int be_cmd_fw_init(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -491,7 +492,8 @@ int be_cmd_fw_clean(struct be_adapter *adapter) if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = (u8 *)wrb_from_mbox(adapter); *wrb++ = 0xFF; @@ -505,7 +507,7 @@ int be_cmd_fw_clean(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } int be_cmd_eq_create(struct be_adapter *adapter, @@ -516,7 +518,8 @@ int be_cmd_eq_create(struct be_adapter *adapter, struct be_dma_mem *q_mem = &eq->dma_mem; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -546,7 +549,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, eq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -558,7 +561,8 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, struct be_cmd_req_mac_query *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -583,7 +587,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, memcpy(mac_addr, resp->mac.addr, ETH_ALEN); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -667,7 +671,8 @@ int be_cmd_cq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -701,7 +706,7 @@ int be_cmd_cq_create(struct be_adapter *adapter, cq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -724,7 +729,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -754,7 +760,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, mccq->id = le16_to_cpu(resp->id); mccq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -769,7 +775,8 @@ int be_cmd_txq_create(struct be_adapter *adapter, void *ctxt; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -801,7 +808,7 @@ int be_cmd_txq_create(struct be_adapter *adapter, txq->created = true; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -816,7 +823,8 @@ int be_cmd_rxq_create(struct be_adapter *adapter, struct be_dma_mem *q_mem = &rxq->dma_mem; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -843,7 +851,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter, *rss_id = resp->rss_id; } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -862,7 +870,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -899,7 +908,7 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -915,7 +924,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, struct be_cmd_req_if_create *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -941,7 +951,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, *pmac_id = le32_to_cpu(resp->pmac_id); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -955,7 +965,8 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) if (adapter->eeh_err) return -EIO; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -970,7 +981,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1060,7 +1071,8 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) struct be_cmd_req_get_fw_version *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1077,7 +1089,7 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1322,7 +1334,8 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, struct be_cmd_req_query_fw_cfg *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1341,7 +1354,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, *caps = le32_to_cpu(resp->function_caps); } - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1352,7 +1365,8 @@ int be_cmd_reset_function(struct be_adapter *adapter) struct be_cmd_req_hdr *req; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1365,7 +1379,7 @@ int be_cmd_reset_function(struct be_adapter *adapter) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } @@ -1376,7 +1390,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) u32 myhash[10]; int status; - spin_lock(&adapter->mbox_lock); + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); @@ -1396,7 +1411,7 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) status = be_mbox_notify_wait(adapter); - spin_unlock(&adapter->mbox_lock); + mutex_unlock(&adapter->mbox_lock); return status; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 93354eee2cfd..fd251b59b7f9 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2677,7 +2677,7 @@ static int be_ctrl_init(struct be_adapter *adapter) } memset(mc_cmd_mem->va, 0, mc_cmd_mem->size); - spin_lock_init(&adapter->mbox_lock); + mutex_init(&adapter->mbox_lock); spin_lock_init(&adapter->mcc_lock); spin_lock_init(&adapter->mcc_cq_lock); diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c index 121b073a6c3f..84fbd4ebd778 100644 --- a/drivers/net/bonding/bond_ipv6.c +++ b/drivers/net/bonding/bond_ipv6.c @@ -88,7 +88,12 @@ static void bond_na_send(struct net_device *slave_dev, } if (vlan_id) { - skb = vlan_put_tag(skb, vlan_id); + /* The Ethernet header is not present yet, so it is + * too early to insert a VLAN tag. Force use of an + * out-of-line tag here and let dev_hard_start_xmit() + * insert it if the slave hardware can't. + */ + skb = __vlan_hwaccel_put_tag(skb, vlan_id); if (!skb) { pr_err("failed to insert VLAN tag\n"); return; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d0ea760ce419..3b16c34ed86e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -418,36 +418,11 @@ struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr) * @bond: bond device that got this skb for tx. * @skb: hw accel VLAN tagged skb to transmit * @slave_dev: slave that is supposed to xmit this skbuff - * - * When the bond gets an skb to transmit that is - * already hardware accelerated VLAN tagged, and it - * needs to relay this skb to a slave that is not - * hw accel capable, the skb needs to be "unaccelerated", - * i.e. strip the hwaccel tag and re-insert it as part - * of the payload. */ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev) { - unsigned short uninitialized_var(vlan_id); - - /* Test vlan_list not vlgrp to catch and handle 802.1p tags */ - if (!list_empty(&bond->vlan_list) && - !(slave_dev->features & NETIF_F_HW_VLAN_TX) && - vlan_get_tag(skb, &vlan_id) == 0) { - skb->dev = slave_dev; - skb = vlan_put_tag(skb, vlan_id); - if (!skb) { - /* vlan_put_tag() frees the skb in case of error, - * so return success here so the calling functions - * won't attempt to free is again. - */ - return 0; - } - } else { - skb->dev = slave_dev; - } - + skb->dev = slave_dev; skb->priority = 1; #ifdef CONFIG_NET_POLL_CONTROLLER if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) { @@ -1203,11 +1178,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_do_fail_over_mac(bond, new_active, old_active); - bond->send_grat_arp = bond->params.num_grat_arp; - bond_send_gratuitous_arp(bond); + if (netif_running(bond->dev)) { + bond->send_grat_arp = bond->params.num_grat_arp; + bond_send_gratuitous_arp(bond); - bond->send_unsol_na = bond->params.num_unsol_na; - bond_send_unsolicited_na(bond); + bond->send_unsol_na = bond->params.num_unsol_na; + bond_send_unsolicited_na(bond); + } write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -1221,8 +1198,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) /* resend IGMP joins since active slave has changed or * all were sent on curr_active_slave */ - if ((USES_PRIMARY(bond->params.mode) && new_active) || - bond->params.mode == BOND_MODE_ROUNDROBIN) { + if (((USES_PRIMARY(bond->params.mode) && new_active) || + bond->params.mode == BOND_MODE_ROUNDROBIN) && + netif_running(bond->dev)) { bond->igmp_retrans = bond->params.resend_igmp; queue_delayed_work(bond->wq, &bond->mcast_work, 0); } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index c2f081352a03..4feeb2d650a4 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -269,11 +269,11 @@ static inline struct slave *bond_get_slave_by_dev(struct bonding *bond, struct n bond_for_each_slave(bond, slave, i) { if (slave->dev == slave_dev) { - break; + return slave; } } - return slave; + return 0; } static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 92bac19ad60a..6dff32196c92 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -940,7 +940,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) &udev->l2_ring_map, GFP_KERNEL | __GFP_COMP); if (!udev->l2_ring) - return -ENOMEM; + goto err_udev; udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size); @@ -948,7 +948,7 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) &udev->l2_buf_map, GFP_KERNEL | __GFP_COMP); if (!udev->l2_buf) - return -ENOMEM; + goto err_dma; write_lock(&cnic_dev_lock); list_add(&udev->list, &cnic_udev_list); @@ -959,6 +959,12 @@ static int cnic_alloc_uio_rings(struct cnic_dev *dev, int pages) cp->udev = udev; return 0; + err_dma: + dma_free_coherent(&udev->pdev->dev, udev->l2_ring_size, + udev->l2_ring, udev->l2_ring_map); + err_udev: + kfree(udev); + return -ENOMEM; } static int cnic_init_uio(struct cnic_dev *dev) diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 1f37ee6b2a26..d6cf502906cf 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -263,6 +263,13 @@ static void ehea_get_ethtool_stats(struct net_device *dev, static int ehea_set_flags(struct net_device *dev, u32 data) { + /* Avoid changing the VLAN flags */ + if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) != + (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN | + ETH_FLAG_TXVLAN))){ + return -EINVAL; + } + return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index aa56963ad558..c353bf3113cc 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -935,7 +935,7 @@ static void epic_init_ring(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(ep->rx_buf_sz + 2); ep->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1233,7 +1233,7 @@ static int epic_rx(struct net_device *dev, int budget) entry = ep->dirty_rx % RX_RING_SIZE; if (ep->rx_skbuff[entry] == NULL) { struct sk_buff *skb; - skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz); + skb = ep->rx_skbuff[entry] = dev_alloc_skb(ep->rx_buf_sz + 2); if (skb == NULL) break; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 9a6485892b3d..80d25ed53344 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1202,7 +1202,7 @@ static void hamachi_init_ring(struct net_device *dev) } /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2); hmp->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1669,7 +1669,7 @@ static int hamachi_rx(struct net_device *dev) entry = hmp->dirty_rx % RX_RING_SIZE; desc = &(hmp->rx_ring[entry]); if (hmp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz + 2); hmp->rx_skbuff[entry] = skb; if (skb == NULL) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 8a4d19e5de06..f1047dd8a526 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -690,6 +690,7 @@ static void block_output(struct net_device *dev, int count, static struct pcmcia_device_id axnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081), PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301), + PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309), diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d05c44692f08..2c158910f7ea 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1493,7 +1493,6 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530), PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110), - PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041), PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452), PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300), diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 39659976a1ac..89294b43c4a9 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1285,6 +1285,11 @@ ppp_push(struct ppp *ppp) } #ifdef CONFIG_PPP_MULTILINK +static bool mp_protocol_compress __read_mostly = true; +module_param(mp_protocol_compress, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(mp_protocol_compress, + "compress protocol id in multilink fragments"); + /* * Divide a packet to be transmitted into fragments and * send them out the individual links. @@ -1347,10 +1352,10 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) if (nfree == 0 || nfree < navail / 2) return 0; /* can't take now, leave it in xmit_pending */ - /* Do protocol field compression (XXX this should be optional) */ + /* Do protocol field compression */ p = skb->data; len = skb->len; - if (*p == 0) { + if (*p == 0 && mp_protocol_compress) { ++p; --len; } diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 0a66fed52e8e..16c62659cdd9 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -412,7 +412,7 @@ static int skfp_driver_init(struct net_device *dev) bp->SharedMemAddr = pci_alloc_consistent(&bp->pdev, bp->SharedMemSize, &bp->SharedMemDMA); - if (!bp->SharedMemSize) { + if (!bp->SharedMemAddr) { printk("could not allocate mem for "); printk("hardware module: %ld byte\n", bp->SharedMemSize); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 4adf12422787..a4f2bd52e546 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -148,7 +148,7 @@ static int full_duplex[MAX_UNITS] = {0, }; * This SUCKS. * We need a much better method to determine if dma_addr_t is 64-bit. */ -#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)) +#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || (defined(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)) /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ #define netdrv_addr_t __le64 diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 3ed2a67bd6d3..b409d7ec4ac1 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1016,7 +1016,7 @@ static void init_ring(struct net_device *dev) /* Fill in the Rx buffers. Handle allocation failure gracefully. */ for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + 2); np->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1407,7 +1407,7 @@ static void refill_rx (struct net_device *dev) struct sk_buff *skb; entry = np->dirty_rx % RX_RING_SIZE; if (np->rx_skbuff[entry] == NULL) { - skb = dev_alloc_skb(np->rx_buf_sz); + skb = dev_alloc_skb(np->rx_buf_sz + 2); np->rx_skbuff[entry] = skb; if (skb == NULL) break; /* Better luck next round. */ diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8b3dc1eb4015..296000bf5a25 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -324,7 +324,7 @@ static int bdx_fw_load(struct bdx_priv *priv) ENTER; master = READ_REG(priv, regINIT_SEMAPHORE); if (!READ_REG(priv, regINIT_STATUS) && master) { - rc = request_firmware(&fw, "tehuti/firmware.bin", &priv->pdev->dev); + rc = request_firmware(&fw, "tehuti/bdx.bin", &priv->pdev->dev); if (rc) goto out; bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size); @@ -2510,4 +2510,4 @@ module_exit(bdx_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(BDX_DRV_DESC); -MODULE_FIRMWARE("tehuti/firmware.bin"); +MODULE_FIRMWARE("tehuti/bdx.bin"); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 30ccbb6d097a..6f97b7bbcbf1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12658,7 +12658,7 @@ static void __devinit tg3_read_vpd(struct tg3 *tp) cnt = pci_read_vpd(tp->pdev, pos, TG3_NVM_VPD_LEN - pos, &vpd_data[pos]); - if (cnt == -ETIMEDOUT || -EINTR) + if (cnt == -ETIMEDOUT || cnt == -EINTR) cnt = 0; else if (cnt < 0) goto out_not_found; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 5b83c3f35f47..a3c46f6a15e7 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1004,7 +1004,6 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) } strcpy(info->driver, KBUILD_MODNAME); - strcpy(info->version, UTS_RELEASE); strcpy(info->bus_info, pci_name(pci_dev)); } diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index aea4645be7f6..6140b56cce53 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1508,6 +1508,10 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x0b95, 0x1780), .driver_info = (unsigned long) &ax88178_info, }, { + // Logitec LAN-GTJ/U2A + USB_DEVICE (0x0789, 0x0160), + .driver_info = (unsigned long) &ax88178_info, +}, { // Linksys USB200M Rev 2 USB_DEVICE (0x13b1, 0x0018), .driver_info = (unsigned long) &ax88772_info, diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index a6281e3987b5..2b791392e788 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -1,5 +1,5 @@ /* - * MOSCHIP MCS7830 based USB 2.0 Ethernet Devices + * MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices * * based on usbnet.c, asix.c and the vendor provided mcs7830 driver * @@ -11,6 +11,9 @@ * * Definitions gathered from MOSCHIP, Data Sheet_7830DA.pdf (thanks!). * + * 2010-12-19: add 7832 USB PID ("functionality same as MCS7830"), + * per active notification by manufacturer + * * TODO: * - support HIF_REG_CONFIG_SLEEPMODE/HIF_REG_CONFIG_TXENABLE (via autopm?) * - implement ethtool_ops get_pauseparam/set_pauseparam @@ -60,6 +63,7 @@ #define MCS7830_MAX_MCAST 64 #define MCS7830_VENDOR_ID 0x9710 +#define MCS7832_PRODUCT_ID 0x7832 #define MCS7830_PRODUCT_ID 0x7830 #define MCS7730_PRODUCT_ID 0x7730 @@ -351,7 +355,7 @@ static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) if (!ret) ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART ); - return ret < 0 ? : 0; + return ret; } @@ -626,7 +630,7 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } static const struct driver_info moschip_info = { - .description = "MOSCHIP 7830/7730 usb-NET adapter", + .description = "MOSCHIP 7830/7832/7730 usb-NET adapter", .bind = mcs7830_bind, .rx_fixup = mcs7830_rx_fixup, .flags = FLAG_ETHER, @@ -645,6 +649,10 @@ static const struct driver_info sitecom_info = { static const struct usb_device_id products[] = { { + USB_DEVICE(MCS7830_VENDOR_ID, MCS7832_PRODUCT_ID), + .driver_info = (unsigned long) &moschip_info, + }, + { USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), .driver_info = (unsigned long) &moschip_info, }, diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 0bbc0c323135..cc83fa71c3ff 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -166,7 +166,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (!(rcv->flags & IFF_UP)) goto tx_drop; - if (dev->features & NETIF_F_NO_CSUM) + /* don't change ip_summed == CHECKSUM_PARTIAL, as that + will cause bad checksum on forwarded packets */ + if (skb->ip_summed == CHECKSUM_NONE) skb->ip_summed = rcv_priv->ip_summed; length = skb->len + ETH_HLEN; diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 25a2722c8a98..1d9aed645723 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -891,7 +891,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local, SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops); - netif_stop_queue(dev); } static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index db540910b110..0e027f787fbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -315,6 +315,7 @@ struct iwl_cfg iwl100_bgn_cfg = { .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, .ht_params = &iwl1000_ht_params, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl100_bg_cfg = { @@ -330,6 +331,7 @@ struct iwl_cfg iwl100_bg_cfg = { .ops = &iwl1000_ops, .mod_params = &iwlagn_mod_params, .base_params = &iwl1000_base_params, + .use_new_eeprom_reading = true, }; MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 11e6532fc573..0ceeaac85eda 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -561,6 +561,7 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = { .ht_params = &iwl6000_ht_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2a_2abg_cfg = { @@ -578,6 +579,7 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2a_2bg_cfg = { @@ -595,6 +597,7 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = { .base_params = &iwl6000_base_params, .need_dc_calib = true, .need_temp_offset_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2agn_cfg = { @@ -616,6 +619,7 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2abg_cfg = { @@ -636,6 +640,7 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2bgn_cfg = { @@ -657,6 +662,7 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_2bg_cfg = { @@ -677,6 +683,7 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_bgn_cfg = { @@ -698,6 +705,7 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6000g2b_bg_cfg = { @@ -718,6 +726,7 @@ struct iwl_cfg iwl6000g2b_bg_cfg = { .need_temp_offset_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; /* @@ -804,6 +813,7 @@ struct iwl_cfg iwl6050g2_bgn_cfg = { .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl6050_2abg_cfg = { @@ -857,6 +867,7 @@ struct iwl_cfg iwl130_bgn_cfg = { .need_dc_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; struct iwl_cfg iwl130_bg_cfg = { @@ -876,6 +887,7 @@ struct iwl_cfg iwl130_bg_cfg = { .need_dc_calib = true, /* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */ .scan_tx_antennas[IEEE80211_BAND_2GHZ] = ANT_A, + .use_new_eeprom_reading = true, }; MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index a650baba0809..9eeeda18748d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -392,7 +392,7 @@ static s8 iwl_update_channel_txpower(struct iwl_priv *priv, /** * iwlcore_eeprom_enhanced_txpower: process enhanced tx power info */ -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +static void iwlcore_eeprom_enhanced_txpower_old(struct iwl_priv *priv) { int eeprom_section_count = 0; int section, element; @@ -419,7 +419,8 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) * always check for valid entry before process * the information */ - if (!enhanced_txpower->common || enhanced_txpower->reserved) + if (!(enhanced_txpower->flags || enhanced_txpower->channel) || + enhanced_txpower->delta_20_in_40) continue; for (element = 0; element < eeprom_section_count; element++) { @@ -452,3 +453,86 @@ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) } } } + +static void +iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *txp, + s8 max_txpower_avg) +{ + int ch_idx; + bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ; + enum ieee80211_band band; + + band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ? + IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; + + for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) { + struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx]; + + /* update matching channel or from common data only */ + if (txp->channel != 0 && ch_info->channel != txp->channel) + continue; + + /* update matching band only */ + if (band != ch_info->band) + continue; + + if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) { + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + + if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg) + ch_info->ht40_max_power_avg = max_txpower_avg; + } +} + +#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT) +#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr) +#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE) + +static void iwlcore_eeprom_enhanced_txpower_new(struct iwl_priv *priv) +{ + struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; + int idx, entries; + __le16 *txp_len; + s8 max_txp_avg, max_txp_avg_halfdbm; + + BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); + + /* the length is in 16-bit words, but we want entries */ + txp_len = (__le16 *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); + entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; + + txp_array = (void *) iwlagn_eeprom_query_addr(priv, EEPROM_TXP_OFFS); + for (idx = 0; idx < entries; idx++) { + txp = &txp_array[idx]; + + /* skip invalid entries */ + if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID)) + continue; + + max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, + &max_txp_avg_halfdbm); + + /* + * Update the user limit values values to the highest + * power supported by any channel + */ + if (max_txp_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txp_avg; + if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm; + + iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg); + } +} + +void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + if (priv->cfg->use_new_eeprom_reading) + iwlcore_eeprom_enhanced_txpower_new(priv); + else + iwlcore_eeprom_enhanced_txpower_old(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index b555edd53354..554afb7d9670 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -569,6 +569,12 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) case INDIRECT_REGULATORY: offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY); break; + case INDIRECT_TXP_LIMIT: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT); + break; + case INDIRECT_TXP_LIMIT_SIZE: + offset = iwl_eeprom_query16(priv, EEPROM_LINK_TXP_LIMIT_SIZE); + break; case INDIRECT_CALIBRATION: offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION); break; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 64527def059f..954ecc2c34c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -390,6 +390,7 @@ struct iwl_cfg { const bool need_temp_offset_calib; /* if used set to true */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; + const bool use_new_eeprom_reading; /* temporary, remove later */ }; /*************************** diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d9b590625ae4..e3a279d2d0b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -120,6 +120,17 @@ struct iwl_eeprom_channel { s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ } __packed; +enum iwl_eeprom_enhanced_txpwr_flags { + IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0), + IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1), + IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2), + IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3), + IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4), + IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5), + IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6), + IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7), +}; + /** * iwl_eeprom_enhanced_txpwr structure * This structure presents the enhanced regulatory tx power limit layout @@ -127,21 +138,23 @@ struct iwl_eeprom_channel { * Enhanced regulatory tx power portion of eeprom image can be broken down * into individual structures; each one is 8 bytes in size and contain the * following information - * @common: (desc + channel) not used by driver, should _NOT_ be "zero" + * @flags: entry flags + * @channel: channel number * @chain_a_max_pwr: chain a max power in 1/2 dBm * @chain_b_max_pwr: chain b max power in 1/2 dBm * @chain_c_max_pwr: chain c max power in 1/2 dBm - * @reserved: not used, should be "zero" + * @delta_20_in_40: 20-in-40 deltas (hi/lo) * @mimo2_max_pwr: mimo2 max power in 1/2 dBm * @mimo3_max_pwr: mimo3 max power in 1/2 dBm * */ struct iwl_eeprom_enhanced_txpwr { - __le16 common; + u8 flags; + u8 channel; s8 chain_a_max; s8 chain_b_max; s8 chain_c_max; - s8 reserved; + u8 delta_20_in_40; s8 mimo2_max; s8 mimo3_max; } __packed; @@ -186,6 +199,8 @@ struct iwl_eeprom_enhanced_txpwr { #define EEPROM_LINK_CALIBRATION (2*0x67) #define EEPROM_LINK_PROCESS_ADJST (2*0x68) #define EEPROM_LINK_OTHERS (2*0x69) +#define EEPROM_LINK_TXP_LIMIT (2*0x6a) +#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b) /* agn regulatory - indirect access */ #define EEPROM_REG_BAND_1_CHANNELS ((0x08)\ @@ -389,6 +404,8 @@ struct iwl_eeprom_calib_info { #define INDIRECT_CALIBRATION 0x00040000 #define INDIRECT_PROCESS_ADJST 0x00050000 #define INDIRECT_OTHERS 0x00060000 +#define INDIRECT_TXP_LIMIT 0x00070000 +#define INDIRECT_TXP_LIMIT_SIZE 0x00080000 #define INDIRECT_ADDRESS 0x00100000 /* General */ diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 373930afc26b..113f4f204657 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -619,7 +619,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, print_ssid(ssid_buf, ssid, ssid_len), LBS_SCAN_RSSI_TO_MBM(rssi)/100); - if (channel || + if (channel && !(channel->flags & IEEE80211_CHAN_DISABLED)) cfg80211_inform_bss(wiphy, channel, bssid, le64_to_cpu(*(__le64 *)tsfdesc), diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index d5bc21e5a02c..2325e56a9b0b 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -43,6 +43,7 @@ MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ + {USB_DEVICE(0x0411, 0x0050)}, /* Buffalo WLI2-USB2-G54 */ {USB_DEVICE(0x045e, 0x00c2)}, /* Microsoft MN-710 */ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */ {USB_DEVICE(0x06b9, 0x0120)}, /* Thomson SpeedTouch 120g */ @@ -56,9 +57,13 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ + {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */ {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */ + {USB_DEVICE(0x1435, 0x0210)}, /* Inventel UR054G */ + {USB_DEVICE(0x15a9, 0x0002)}, /* Gemtek WUBI-100GW 802.11g */ {USB_DEVICE(0x1630, 0x0005)}, /* 2Wire 802.11g USB (v1) / Z-Com */ + {USB_DEVICE(0x182d, 0x096b)}, /* Sitecom WL-107 */ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */ {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ @@ -94,6 +99,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */ {USB_DEVICE(0x1668, 0x1050)}, /* Actiontec 802UIG-1 */ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */ + {USB_DEVICE(0x2001, 0x3705)}, /* D-Link DWL-G120 rev C1 */ {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */ {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */ diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b26739535986..09a67905c230 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -912,6 +912,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags); + __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags); if (!modparam_nohwcrypt) __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags); diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 94fe589acfaa..ab43e7ca2a23 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -664,6 +664,7 @@ enum rt2x00_flags { DRIVER_REQUIRE_COPY_IV, DRIVER_REQUIRE_L2PAD, DRIVER_REQUIRE_TXSTATUS_FIFO, + DRIVER_REQUIRE_TASKLET_CONTEXT, /* * Driver features diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5ba79b935f09..d019830ca840 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -390,9 +390,12 @@ void rt2x00lib_txdone(struct queue_entry *entry, * through a mac80211 library call (RTS/CTS) then we should not * send the status report back. */ - if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) - ieee80211_tx_status(rt2x00dev->hw, entry->skb); - else + if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) { + if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags)) + ieee80211_tx_status(rt2x00dev->hw, entry->skb); + else + ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb); + } else dev_kfree_skb_any(entry->skb); /* diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index cd1b3dcd61db..ec47e22fa186 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -744,7 +744,7 @@ static int yellowfin_init_ring(struct net_device *dev) } for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2); yp->rx_skbuff[i] = skb; if (skb == NULL) break; @@ -1157,7 +1157,7 @@ static int yellowfin_rx(struct net_device *dev) for (; yp->cur_rx - yp->dirty_rx > 0; yp->dirty_rx++) { entry = yp->dirty_rx % RX_RING_SIZE; if (yp->rx_skbuff[entry] == NULL) { - struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz); + struct sk_buff *skb = dev_alloc_skb(yp->rx_buf_sz + 2); if (skb == NULL) break; /* Better luck next round. */ yp->rx_skbuff[entry] = skb; diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index c85d3c7421fc..f37fbeb66a44 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -61,7 +61,7 @@ void of_i2c_register_devices(struct i2c_adapter *adap) info.of_node = of_node_get(node); info.archdata = &dev_ad; - request_module("%s", info.type); + request_module("%s%s", I2C_MODULE_PREFIX, info.type); result = i2c_new_device(adap, &info); if (result == NULL) { diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 003170ea2e39..69546e9213dd 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -64,77 +64,6 @@ void pci_bus_remove_resources(struct pci_bus *bus) } } -static bool pci_bus_resource_better(struct resource *res1, bool pos1, - struct resource *res2, bool pos2) -{ - /* If exactly one is positive decode, always prefer that one */ - if (pos1 != pos2) - return pos1 ? true : false; - - /* Prefer the one that contains the highest address */ - if (res1->end != res2->end) - return (res1->end > res2->end) ? true : false; - - /* Otherwise, prefer the one with highest "center of gravity" */ - if (res1->start != res2->start) - return (res1->start > res2->start) ? true : false; - - /* Otherwise, choose one arbitrarily (but consistently) */ - return (res1 > res2) ? true : false; -} - -static bool pci_bus_resource_positive(struct pci_bus *bus, struct resource *res) -{ - struct pci_bus_resource *bus_res; - - /* - * This relies on the fact that pci_bus.resource[] refers to P2P or - * CardBus bridge base/limit registers, which are always positively - * decoded. The pci_bus.resources list contains host bridge or - * subtractively decoded resources. - */ - list_for_each_entry(bus_res, &bus->resources, list) { - if (bus_res->res == res) - return (bus_res->flags & PCI_SUBTRACTIVE_DECODE) ? - false : true; - } - return true; -} - -/* - * Find the next-best bus resource after the cursor "res". If the cursor is - * NULL, return the best resource. "Best" means that we prefer positive - * decode regions over subtractive decode, then those at higher addresses. - */ -static struct resource *pci_bus_find_resource_prev(struct pci_bus *bus, - unsigned int type, - struct resource *res) -{ - bool res_pos, r_pos, prev_pos = false; - struct resource *r, *prev = NULL; - int i; - - res_pos = pci_bus_resource_positive(bus, res); - pci_bus_for_each_resource(bus, r, i) { - if (!r) - continue; - - if ((r->flags & IORESOURCE_TYPE_BITS) != type) - continue; - - r_pos = pci_bus_resource_positive(bus, r); - if (!res || pci_bus_resource_better(res, res_pos, r, r_pos)) { - if (!prev || pci_bus_resource_better(r, r_pos, - prev, prev_pos)) { - prev = r; - prev_pos = r_pos; - } - } - } - - return prev; -} - /** * pci_bus_alloc_resource - allocate a resource from a parent bus * @bus: PCI bus @@ -160,10 +89,9 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, resource_size_t), void *alignf_data) { - int ret = -ENOMEM; + int i, ret = -ENOMEM; struct resource *r; resource_size_t max = -1; - unsigned int type = res->flags & IORESOURCE_TYPE_BITS; type_mask |= IORESOURCE_IO | IORESOURCE_MEM; @@ -171,9 +99,10 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, if (!(res->flags & IORESOURCE_MEM_64)) max = PCIBIOS_MAX_MEM_32; - /* Look for space at highest addresses first */ - r = pci_bus_find_resource_prev(bus, type, NULL); - for ( ; r; r = pci_bus_find_resource_prev(bus, type, r)) { + pci_bus_for_each_resource(bus, r, i) { + if (!r) + continue; + /* type_mask must match */ if ((res->flags ^ r->flags) & type_mask) continue; diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 0157708d474d..09933eb9126b 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1417,6 +1417,11 @@ int __init enable_drhd_fault_handling(void) (unsigned long long)drhd->reg_base_addr, ret); return -1; } + + /* + * Clear any previous faults. + */ + dmar_fault(iommu->irq, iommu); } return 0; diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c index 2574700db461..5f7226223a62 100644 --- a/drivers/pci/hotplug/pciehp_acpi.c +++ b/drivers/pci/hotplug/pciehp_acpi.c @@ -115,7 +115,8 @@ static struct pcie_port_service_driver __initdata dummy_driver = { static int __init select_detection_mode(void) { struct dummy_slot *slot, *tmp; - pcie_port_service_register(&dummy_driver); + if (pcie_port_service_register(&dummy_driver)) + return PCIEHP_DETECT_ACPI; pcie_port_service_unregister(&dummy_driver); list_for_each_entry_safe(slot, tmp, &dummy_slots, list) { list_del(&slot->list); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6f9350cabbd5..53a786fd0d40 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2329,6 +2329,9 @@ static void __devinit nvbridge_check_legacy_irq_routing(struct pci_dev *dev) { u32 cfg; + if (!pci_find_capability(dev, PCI_CAP_ID_HT)) + return; + pci_read_config_dword(dev, 0x74, &cfg); if (cfg & ((1 << 2) | (1 << 15))) { @@ -2764,6 +2767,29 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_m DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); #endif /*CONFIG_MMC_RICOH_MMC*/ +#if defined(CONFIG_DMAR) || defined(CONFIG_INTR_REMAP) +#define VTUNCERRMSK_REG 0x1ac +#define VTD_MSK_SPEC_ERRORS (1 << 31) +/* + * This is a quirk for masking vt-d spec defined errors to platform error + * handling logic. With out this, platforms using Intel 7500, 5500 chipsets + * (and the derivative chipsets like X58 etc) seem to generate NMI/SMI (based + * on the RAS config settings of the platform) when a vt-d fault happens. + * The resulting SMI caused the system to hang. + * + * VT-d spec related errors are already handled by the VT-d OS code, so no + * need to report the same error through other channels. + */ +static void vtd_mask_spec_errors(struct pci_dev *dev) +{ + u32 word; + + pci_read_config_dword(dev, VTUNCERRMSK_REG, &word); + pci_write_config_dword(dev, VTUNCERRMSK_REG, word | VTD_MSK_SPEC_ERRORS); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors); +#endif static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 9a44a90dcf7a..29935ea921df 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -50,8 +50,9 @@ sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o -sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o +sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-$(CONFIG_SA1100_NANOENGINE) += sa1100_nanoengine.o sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 6b228590b3fd..fb9740d3e9a7 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -53,6 +53,9 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600) pcmcia_h3600_init, #endif +#ifdef CONFIG_SA1100_NANOENGINE + pcmcia_nanoengine_init, +#endif #ifdef CONFIG_SA1100_SHANNON pcmcia_shannon_init, #endif diff --git a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h index 794f96a35bba..adb08dbc723f 100644 --- a/drivers/pcmcia/sa1100_generic.h +++ b/drivers/pcmcia/sa1100_generic.h @@ -13,6 +13,7 @@ extern int pcmcia_freebird_init(struct device *); extern int pcmcia_gcplus_init(struct device *); extern int pcmcia_graphicsmaster_init(struct device *); extern int pcmcia_h3600_init(struct device *); +extern int pcmcia_nanoengine_init(struct device *); extern int pcmcia_pangolin_init(struct device *); extern int pcmcia_pfs168_init(struct device *); extern int pcmcia_shannon_init(struct device *); diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c new file mode 100644 index 000000000000..3d2652e2f5ae --- /dev/null +++ b/drivers/pcmcia/sa1100_nanoengine.c @@ -0,0 +1,219 @@ +/* + * drivers/pcmcia/sa1100_nanoengine.c + * + * PCMCIA implementation routines for BSI nanoEngine. + * + * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine + * board you should carefully read this: + * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/ + * + * Copyright (C) 2010 Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br> + * + * Based on original work for kernel 2.4 by + * Miguel Freitas <miguel@cpti.cetuc.puc-rio.br> + * + * 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/device.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/signal.h> + +#include <asm/mach-types.h> +#include <asm/irq.h> + +#include <mach/hardware.h> +#include <mach/nanoengine.h> + +#include "sa1100_generic.h" + +static struct pcmcia_irqs irqs_skt0[] = { + /* socket, IRQ, name */ + { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" }, +}; + +static struct pcmcia_irqs irqs_skt1[] = { + /* socket, IRQ, name */ + { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" }, +}; + +struct nanoengine_pins { + unsigned input_pins; + unsigned output_pins; + unsigned clear_outputs; + unsigned transition_pins; + unsigned pci_irq; + struct pcmcia_irqs *pcmcia_irqs; + unsigned pcmcia_irqs_size; +}; + +static struct nanoengine_pins nano_skts[] = { + { + .input_pins = GPIO_PC_READY0 | GPIO_PC_CD0, + .output_pins = GPIO_PC_RESET0, + .clear_outputs = GPIO_PC_RESET0, + .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD0, + .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY0, + .pcmcia_irqs = irqs_skt0, + .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt0) + }, { + .input_pins = GPIO_PC_READY1 | GPIO_PC_CD1, + .output_pins = GPIO_PC_RESET1, + .clear_outputs = GPIO_PC_RESET1, + .transition_pins = NANOENGINE_IRQ_GPIO_PC_CD1, + .pci_irq = NANOENGINE_IRQ_GPIO_PC_READY1, + .pcmcia_irqs = irqs_skt1, + .pcmcia_irqs_size = ARRAY_SIZE(irqs_skt1) + } +}; + +unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts); + +static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return -ENXIO; + + GPDR &= ~nano_skts[i].input_pins; + GPDR |= nano_skts[i].output_pins; + GPCR = nano_skts[i].clear_outputs; + set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH); + skt->socket.pci_irq = nano_skts[i].pci_irq; + + return soc_pcmcia_request_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +/* + * Release all resources. + */ +static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_free_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +static int nanoengine_pcmcia_configure_socket( + struct soc_pcmcia_socket *skt, const socket_state_t *state) +{ + unsigned reset; + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return -ENXIO; + + switch (i) { + case 0: + reset = GPIO_PC_RESET0; + break; + case 1: + reset = GPIO_PC_RESET1; + break; + default: + return -ENXIO; + } + + if (state->flags & SS_RESET) + GPSR = reset; + else + GPCR = reset; + + return 0; +} + +static void nanoengine_pcmcia_socket_state( + struct soc_pcmcia_socket *skt, struct pcmcia_state *state) +{ + unsigned long levels = GPLR; + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + memset(state, 0, sizeof(struct pcmcia_state)); + switch (i) { + case 0: + state->ready = (levels & GPIO_PC_READY0) ? 1 : 0; + state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0; + break; + case 1: + state->ready = (levels & GPIO_PC_READY1) ? 1 : 0; + state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0; + break; + default: + return; + } + state->bvd1 = 1; + state->bvd2 = 1; + state->wrprot = 0; /* Not available */ + state->vs_3v = 1; /* Can only apply 3.3V */ + state->vs_Xv = 0; +} + +/* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ +static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_enable_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +/* + * Disable card status IRQs on suspend. + */ +static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) +{ + unsigned i = skt->nr; + + if (i >= num_nano_pcmcia_sockets) + return; + + soc_pcmcia_disable_irqs(skt, + nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size); +} + +static struct pcmcia_low_level nanoengine_pcmcia_ops = { + .owner = THIS_MODULE, + + .hw_init = nanoengine_pcmcia_hw_init, + .hw_shutdown = nanoengine_pcmcia_hw_shutdown, + + .configure_socket = nanoengine_pcmcia_configure_socket, + .socket_state = nanoengine_pcmcia_socket_state, + .socket_init = nanoengine_pcmcia_socket_init, + .socket_suspend = nanoengine_pcmcia_socket_suspend, +}; + +int pcmcia_nanoengine_init(struct device *dev) +{ + int ret = -ENODEV; + + if (machine_is_nanoengine()) + ret = sa11xx_drv_pcmcia_probe( + dev, &nanoengine_pcmcia_ops, 0, 2); + + return ret; +} + diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 2fe8cb8e95cd..5a9a392eacdf 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -31,20 +31,20 @@ ======================================================================*/ -#include <linux/module.h> -#include <linux/moduleparam.h> +#include <linux/cpufreq.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> #include <linux/kernel.h> -#include <linux/timer.h> #include <linux/mm.h> +#include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/mutex.h> -#include <linux/interrupt.h> -#include <linux/irq.h> #include <linux/spinlock.h> -#include <linux/cpufreq.h> +#include <linux/timer.h> #include <mach/hardware.h> -#include <asm/io.h> #include <asm/system.h> #include "soc_common.h" @@ -74,7 +74,8 @@ EXPORT_SYMBOL(soc_pcmcia_debug); #endif -#define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket) +#define to_soc_pcmcia_socket(x) \ + container_of(x, struct soc_pcmcia_socket, socket) static unsigned short calc_speed(unsigned short *spds, int num, unsigned short dflt) @@ -91,11 +92,15 @@ calc_speed(unsigned short *spds, int num, unsigned short dflt) return speed; } -void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing) +void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, + struct soc_pcmcia_timing *timing) { - timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); - timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); - timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); + timing->io = + calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS); + timing->mem = + calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); + timing->attr = + calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS); } EXPORT_SYMBOL(soc_common_pcmcia_get_timing); @@ -137,8 +142,8 @@ static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt) * * Convert PCMCIA socket state to our socket configure structure. */ -static int -soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *state) +static int soc_common_pcmcia_config_skt( + struct soc_pcmcia_socket *skt, socket_state_t *state) { int ret; @@ -150,7 +155,8 @@ soc_common_pcmcia_config_skt(struct soc_pcmcia_socket *skt, socket_state_t *stat */ if (skt->irq_state != 1 && state->io_irq) { skt->irq_state = 1; - set_irq_type(skt->socket.pci_irq, IRQ_TYPE_EDGE_FALLING); + set_irq_type(skt->socket.pci_irq, + IRQ_TYPE_EDGE_FALLING); } else if (skt->irq_state == 1 && state->io_irq == 0) { skt->irq_state = 0; set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); @@ -304,24 +310,24 @@ soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) * of power configuration, reset, &c. We also record the value of * `state' in order to regurgitate it to the PCMCIA core later. */ -static int -soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) +static int soc_common_pcmcia_set_socket( + struct pcmcia_socket *sock, socket_state_t *state) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); - debug(skt, 2, "mask: %s%s%s%s%s%sflags: %s%s%s%s%s%sVcc %d Vpp %d irq %d\n", - (state->csc_mask==0)?"<NONE> ":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"<NONE> ":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"", + debug(skt, 2, "mask: %s%s%s%s%s%s flags: %s%s%s%s%s%s Vcc %d Vpp %d irq %d\n", + (state->csc_mask == 0) ? "<NONE> " : "", + (state->csc_mask & SS_DETECT) ? "DETECT " : "", + (state->csc_mask & SS_READY) ? "READY " : "", + (state->csc_mask & SS_BATDEAD) ? "BATDEAD " : "", + (state->csc_mask & SS_BATWARN) ? "BATWARN " : "", + (state->csc_mask & SS_STSCHG) ? "STSCHG " : "", + (state->flags == 0) ? "<NONE> " : "", + (state->flags & SS_PWR_AUTO) ? "PWR_AUTO " : "", + (state->flags & SS_IOCARD) ? "IOCARD " : "", + (state->flags & SS_RESET) ? "RESET " : "", + (state->flags & SS_SPKR_ENA) ? "SPKR_ENA " : "", + (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA " : "", state->Vcc, state->Vpp, state->io_irq); return soc_common_pcmcia_config_skt(skt, state); @@ -336,8 +342,8 @@ soc_common_pcmcia_set_socket(struct pcmcia_socket *sock, socket_state_t *state) * * Returns: 0 on success, -1 on error */ -static int -soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *map) +static int soc_common_pcmcia_set_io_map( + struct pcmcia_socket *sock, struct pccard_io_map *map) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); unsigned short speed = map->speed; @@ -346,14 +352,14 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m map->map, map->speed, (unsigned long long)map->start, (unsigned long long)map->stop); debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"<NONE>":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", - (map->flags&MAP_PREFETCH)?"PREFETCH ":""); + (map->flags == 0) ? "<NONE>" : "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "", + (map->flags & MAP_PREFETCH) ? "PREFETCH " : ""); if (map->map >= MAX_IO_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __func__, @@ -390,8 +396,8 @@ soc_common_pcmcia_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *m * * Returns: 0 on success, -ERRNO on error */ -static int -soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *map) +static int soc_common_pcmcia_set_mem_map( + struct pcmcia_socket *sock, struct pccard_mem_map *map) { struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); struct resource *res; @@ -400,14 +406,14 @@ soc_common_pcmcia_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map debug(skt, 2, "map %u speed %u card_start %08x\n", map->map, map->speed, map->card_start); debug(skt, 2, "flags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"<NONE>":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_ATTRIB)?"ATTRIB ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); + (map->flags == 0) ? "<NONE>" : "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_ATTRIB) ? "ATTRIB " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : ""); if (map->map >= MAX_WIN) return -EINVAL; @@ -462,8 +468,8 @@ static struct bittbl conf_bits[] = { { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, }; -static void -dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) +static void dump_bits(char **p, const char *prefix, + unsigned int val, struct bittbl *bits, int sz) { char *b = *p; int i; @@ -481,13 +487,14 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_status( + struct device *dev, struct device_attribute *attr, char *buf) { struct soc_pcmcia_socket *skt = container_of(dev, struct soc_pcmcia_socket, socket.dev); char *p = buf; - p+=sprintf(p, "slot : %d\n", skt->nr); + p += sprintf(p, "slot : %d\n", skt->nr); dump_bits(&p, "status", skt->status, status_bits, ARRAY_SIZE(status_bits)); @@ -496,12 +503,12 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, ch dump_bits(&p, "cs_flags", skt->cs_state.flags, conf_bits, ARRAY_SIZE(conf_bits)); - p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); - p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); - p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, + p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p += sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->socket.pci_irq); if (skt->ops->show_timing) - p+=skt->ops->show_timing(skt, p); + p += skt->ops->show_timing(skt, p); return p-buf; } @@ -594,7 +601,7 @@ soc_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data) mutex_lock(&soc_pcmcia_sockets_lock); list_for_each_entry(skt, &soc_pcmcia_sockets, node) - if ( skt->ops->frequency_change ) + if (skt->ops->frequency_change) ret += skt->ops->frequency_change(skt, val, freqs); mutex_unlock(&soc_pcmcia_sockets_lock); @@ -620,7 +627,8 @@ fs_initcall(soc_pcmcia_cpufreq_register); static void soc_pcmcia_cpufreq_unregister(void) { - cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_unregister_notifier(&soc_pcmcia_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); } module_exit(soc_pcmcia_cpufreq_unregister); diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index c44a5e8b8b82..f0b3ad13c273 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -75,6 +75,7 @@ #include <drm/i915_drm.h> #include <asm/msr.h> #include <asm/processor.h> +#include "intel_ips.h" #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 @@ -245,6 +246,7 @@ #define thm_writel(off, val) writel((val), ips->regmap + (off)) static const int IPS_ADJUST_PERIOD = 5000; /* ms */ +static bool late_i915_load = false; /* For initial average collection */ static const int IPS_SAMPLE_PERIOD = 200; /* ms */ @@ -339,6 +341,9 @@ struct ips_driver { u64 orig_turbo_ratios; }; +static bool +ips_gpu_turbo_enabled(struct ips_driver *ips); + /** * ips_cpu_busy - is CPU busy? * @ips: IPS driver struct @@ -517,7 +522,7 @@ static void ips_disable_cpu_turbo(struct ips_driver *ips) */ static bool ips_gpu_busy(struct ips_driver *ips) { - if (!ips->gpu_turbo_enabled) + if (!ips_gpu_turbo_enabled(ips)) return false; return ips->gpu_busy(); @@ -532,7 +537,7 @@ static bool ips_gpu_busy(struct ips_driver *ips) */ static void ips_gpu_raise(struct ips_driver *ips) { - if (!ips->gpu_turbo_enabled) + if (!ips_gpu_turbo_enabled(ips)) return; if (!ips->gpu_raise()) @@ -549,7 +554,7 @@ static void ips_gpu_raise(struct ips_driver *ips) */ static void ips_gpu_lower(struct ips_driver *ips) { - if (!ips->gpu_turbo_enabled) + if (!ips_gpu_turbo_enabled(ips)) return; if (!ips->gpu_lower()) @@ -1454,6 +1459,31 @@ out_err: return false; } +static bool +ips_gpu_turbo_enabled(struct ips_driver *ips) +{ + if (!ips->gpu_busy && late_i915_load) { + if (ips_get_i915_syms(ips)) { + dev_info(&ips->dev->dev, + "i915 driver attached, reenabling gpu turbo\n"); + ips->gpu_turbo_enabled = !(thm_readl(THM_HTS) & HTS_GTD_DIS); + } + } + + return ips->gpu_turbo_enabled; +} + +void +ips_link_to_i915_driver() +{ + /* We can't cleanly get at the various ips_driver structs from + * this caller (the i915 driver), so just set a flag saying + * that it's time to try getting the symbols again. + */ + late_i915_load = true; +} +EXPORT_SYMBOL_GPL(ips_link_to_i915_driver); + static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), }, diff --git a/drivers/platform/x86/intel_ips.h b/drivers/platform/x86/intel_ips.h new file mode 100644 index 000000000000..73299beff5b3 --- /dev/null +++ b/drivers/platform/x86/intel_ips.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + */ + +void ips_link_to_i915_driver(void); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 90cf0a6ff23e..dd14e202c2c8 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -207,7 +207,7 @@ static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) { struct rs5c372 *rs5c = i2c_get_clientdata(client); - unsigned char buf[8]; + unsigned char buf[7]; int addr; dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d " diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e4a44b641702..88ea52b8647a 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -39,10 +39,10 @@ #include <mach/regs-ost.h> #endif -#define RTC_DEF_DIVIDER 32768 - 1 +#define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 -static unsigned long rtc_freq = 1024; +static const unsigned long RTC_FREQ = 1024; static unsigned long timer_freq; static struct rtc_time rtc_alarm; static DEFINE_SPINLOCK(sa1100_rtc_lock); @@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm) * Calculate the next alarm time given the requested alarm time mask * and the current time. */ -static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, + struct rtc_time *alrm) { unsigned long next_time; unsigned long now_time; @@ -116,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtsr = RTSR; /* clear interrupt sources */ RTSR = 0; - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_probe(). */ + if (rtsr & (RTSR_ALE | RTSR_HZE)) { + /* This is the original code, before there was the if test + * above. This code does not clear interrupts that were not + * enabled. */ + RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + } else { + /* For some reason, it is possible to enter this routine + * without interruptions enabled, it has been tested with + * several units (Bug in SA11xx chip?). + * + * This situation leads to an infinite "loop" of interrupt + * routine calling and as a result the processor seems to + * lock on its first call to open(). */ + RTSR = RTSR_AL | RTSR_HZ; + } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) @@ -139,8 +156,58 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int sa1100_irq_set_freq(struct device *dev, int freq) +{ + if (freq < 1 || freq > timer_freq) { + return -EINVAL; + } else { + struct rtc_device *rtc = (struct rtc_device *)dev; + + rtc->irq_freq = freq; + + return 0; + } +} + static int rtc_timer1_count; +static int sa1100_irq_set_state(struct device *dev, int enabled) +{ + spin_lock_irq(&sa1100_rtc_lock); + if (enabled) { + struct rtc_device *rtc = (struct rtc_device *)dev; + + OSMR1 = timer_freq / rtc->irq_freq + OSCR; + OIER |= OIER_E1; + rtc_timer1_count = 1; + } else { + OIER &= ~OIER_E1; + } + spin_unlock_irq(&sa1100_rtc_lock); + + return 0; +} + +static inline int sa1100_timer1_retrigger(struct rtc_device *rtc) +{ + unsigned long diff; + unsigned long period = timer_freq / rtc->irq_freq; + + spin_lock_irq(&sa1100_rtc_lock); + + do { + OSMR1 += period; + diff = OSMR1 - OSCR; + /* If OSCR > OSMR1, diff is a very large number (unsigned + * math). This means we have a lost interrupt. */ + } while (diff > period); + OIER |= OIER_E1; + + spin_unlock_irq(&sa1100_rtc_lock); + + return 0; +} + static irqreturn_t timer1_interrupt(int irq, void *dev_id) { struct platform_device *pdev = to_platform_device(dev_id); @@ -158,7 +225,11 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF); if (rtc_timer1_count == 1) - rtc_timer1_count = (rtc_freq * ((1 << 30) / (timer_freq >> 2))); + rtc_timer1_count = + (rtc->irq_freq * ((1 << 30) / (timer_freq >> 2))); + + /* retrigger. */ + sa1100_timer1_retrigger(rtc); return IRQ_HANDLED; } @@ -166,8 +237,10 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id) static int sa1100_rtc_read_callback(struct device *dev, int data) { if (data & RTC_PF) { + struct rtc_device *rtc = (struct rtc_device *)dev; + /* interpolate missed periods and set match for the next */ - unsigned long period = timer_freq / rtc_freq; + unsigned long period = timer_freq / rtc->irq_freq; unsigned long oscr = OSCR; unsigned long osmr1 = OSMR1; unsigned long missed = (oscr - osmr1)/period; @@ -178,7 +251,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) * Here we compare (match - OSCR) 8 instead of 0 -- * see comment in pxa_timer_interrupt() for explanation. */ - while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { + while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) { data += 0x100; OSSR = OSSR_M1; /* clear match on timer 1 */ OSMR1 = osmr1 + period; @@ -190,25 +263,29 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) static int sa1100_rtc_open(struct device *dev) { int ret; + struct rtc_device *rtc = (struct rtc_device *)dev; ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc 1Hz", dev); + "rtc 1Hz", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); goto fail_ui; } ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc Alrm", dev); + "rtc Alrm", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, - "rtc timer", dev); + "rtc timer", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; } + rtc->max_user_freq = RTC_FREQ; + sa1100_irq_set_freq(dev, RTC_FREQ); + return 0; fail_pi: @@ -236,7 +313,7 @@ static void sa1100_rtc_release(struct device *dev) static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - switch(cmd) { + switch (cmd) { case RTC_AIE_OFF: spin_lock_irq(&sa1100_rtc_lock); RTSR &= ~RTSR_ALE; @@ -257,25 +334,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, RTSR |= RTSR_HZE; spin_unlock_irq(&sa1100_rtc_lock); return 0; - case RTC_PIE_OFF: - spin_lock_irq(&sa1100_rtc_lock); - OIER &= ~OIER_E1; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_PIE_ON: - spin_lock_irq(&sa1100_rtc_lock); - OSMR1 = timer_freq / rtc_freq + OSCR; - OIER |= OIER_E1; - rtc_timer1_count = 1; - spin_unlock_irq(&sa1100_rtc_lock); - return 0; - case RTC_IRQP_READ: - return put_user(rtc_freq, (unsigned long *)arg); - case RTC_IRQP_SET: - if (arg < 1 || arg > timer_freq) - return -EINVAL; - rtc_freq = arg; - return 0; } return -ENOIOCTLCMD; } @@ -327,12 +385,15 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { + struct rtc_device *rtc = (struct rtc_device *)dev; + seq_printf(seq, "trim/divider\t: 0x%08x\n", (u32) RTTR); seq_printf(seq, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no"); seq_printf(seq, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); - seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); + seq_printf(seq, "periodic_freq\t: %d\n", rtc->irq_freq); + seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); return 0; } @@ -347,6 +408,8 @@ static const struct rtc_class_ops sa1100_rtc_ops = { .read_alarm = sa1100_rtc_read_alarm, .set_alarm = sa1100_rtc_set_alarm, .proc = sa1100_rtc_proc, + .irq_set_freq = sa1100_irq_set_freq, + .irq_set_state = sa1100_irq_set_state, }; static int sa1100_rtc_probe(struct platform_device *pdev) @@ -364,7 +427,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) */ if (RTTR == 0) { RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); + dev_warn(&pdev->dev, "warning: " + "initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ RCNR = 0; } @@ -372,13 +436,42 @@ static int sa1100_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, - THIS_MODULE); + THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); platform_set_drvdata(pdev, rtc); + /* Set the irq_freq */ + /*TODO: Find out who is messing with this value after we initialize + * it here.*/ + rtc->irq_freq = RTC_FREQ; + + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_interrupt(). + * + * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an + * interrupt pending, even though interrupts were never enabled. + * In this case, this bit it must be reset before enabling + * interruptions to avoid a nonexistent interrupt to occur. + * + * In principle, the same problem would apply to bit 0, although it has + * never been observed to happen. + * + * This issue is addressed both here and in sa1100_rtc_interrupt(). + * If the issue is not addressed here, in the times when the processor + * wakes up with the bit set there will be one spurious interrupt. + * + * The issue is also dealt with in sa1100_rtc_interrupt() to be on the + * safe side, once the condition that lead to this strange + * initialization is unknown and could in principle happen during + * normal processing. + * + * Notice that clearing bit 1 and 0 is accomplished by writting ONES to + * the corresponding bits in RTSR. */ + RTSR = RTSR_AL | RTSR_HZ; + return 0; } @@ -386,7 +479,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); - if (rtc) + if (rtc) rtc_device_unregister(rtc); return 0; diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index c94502dfac66..045d7e87b632 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -677,7 +677,7 @@ bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, bfa_trc(fabric->fcs, event); wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Port is isolated due to VF_ID mismatch. " "PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.", pwwn_ptr, fabric->fcs->port_vfid, @@ -1411,7 +1411,7 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport)); wwn2str(fwwn_ptr, bfa_fcs_lport_get_fabric_name(&fabric->bport)); - BFA_LOG(KERN_WARNING, bfad, log_level, + BFA_LOG(KERN_WARNING, bfad, bfa_log_level, "Base port WWN = %s Fabric WWN = %s\n", pwwn_ptr, fwwn_ptr); } diff --git a/drivers/scsi/bfa/bfa_fcs_fcpim.c b/drivers/scsi/bfa/bfa_fcs_fcpim.c index 9662bcdeb41d..413b58eef93a 100644 --- a/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcs_fcpim.c @@ -261,7 +261,7 @@ bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, bfa_fcb_itnim_online(itnim->itnim_drv); wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); wwn2str(rpwwn_buf, itnim->rport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Target (WWN = %s) is online for initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf); break; @@ -301,11 +301,11 @@ bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); wwn2str(rpwwn_buf, itnim->rport->pwwn); if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Target (WWN = %s) connectivity lost for " "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf); else - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Target (WWN = %s) offlined by initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf); break; diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 377cbfff6f2e..8d651309302b 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -491,7 +491,7 @@ bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port) __port_action[port->fabric->fab_type].online(port); wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Logical port online: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); @@ -512,11 +512,11 @@ bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port) wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Logical port lost fabric connectivity: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); else - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Logical port taken offline: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); @@ -573,7 +573,7 @@ bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port) char lpwwn_buf[BFA_STRING_32]; wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Logical port deleted: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); @@ -878,7 +878,7 @@ bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, vport ? vport->vport_drv : NULL); wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport)); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "New logical port created: WWN = %s Role = %s\n", lpwwn_buf, "Initiator"); diff --git a/drivers/scsi/bfa/bfa_fcs_rport.c b/drivers/scsi/bfa/bfa_fcs_rport.c index 47f35c0ef29a..cf4a6e73e60d 100644 --- a/drivers/scsi/bfa/bfa_fcs_rport.c +++ b/drivers/scsi/bfa/bfa_fcs_rport.c @@ -2056,7 +2056,7 @@ bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); wwn2str(rpwwn_buf, rport->pwwn); if (!BFA_FCS_PID_IS_WKA(rport->pid)) - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Remote port (WWN = %s) online for logical port (WWN = %s)\n", rpwwn_buf, lpwwn_buf); } @@ -2075,12 +2075,12 @@ bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) wwn2str(rpwwn_buf, rport->pwwn); if (!BFA_FCS_PID_IS_WKA(rport->pid)) { if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE) - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Remote port (WWN = %s) connectivity lost for " "logical port (WWN = %s)\n", rpwwn_buf, lpwwn_buf); else - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Remote port (WWN = %s) offlined by " "logical port (WWN = %s)\n", rpwwn_buf, lpwwn_buf); diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 54475b53a5ab..9f4aa391ea9d 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -402,7 +402,7 @@ bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); bfa_ioc_hb_monitor(ioc); - BFA_LOG(KERN_INFO, bfad, log_level, "IOC enabled\n"); + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n"); } static void @@ -444,7 +444,7 @@ bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc) { struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; bfa_iocpf_disable(ioc); - BFA_LOG(KERN_INFO, bfad, log_level, "IOC disabled\n"); + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n"); } /* @@ -565,7 +565,7 @@ bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc) notify->cbfn(notify->cbarg); } - BFA_LOG(KERN_CRIT, bfad, log_level, + BFA_LOG(KERN_CRIT, bfad, bfa_log_level, "Heart Beat of IOC has failed\n"); } @@ -1812,7 +1812,7 @@ bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc) * Provide enable completion callback. */ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - BFA_LOG(KERN_WARNING, bfad, log_level, + BFA_LOG(KERN_WARNING, bfad, bfa_log_level, "Running firmware version is incompatible " "with the driver version\n"); } diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index c768143f4805..37e16ac8f249 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -2138,7 +2138,7 @@ bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port disabled: WWN = %s\n", pwwn_buf); break; @@ -2198,7 +2198,7 @@ bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port disabled: WWN = %s\n", pwwn_buf); break; @@ -2251,7 +2251,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port online: WWN = %s\n", pwwn_buf); break; @@ -2277,7 +2277,7 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port disabled: WWN = %s\n", pwwn_buf); break; @@ -2322,9 +2322,9 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port offline: WWN = %s\n", pwwn_buf); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port disabled: WWN = %s\n", pwwn_buf); break; @@ -2336,10 +2336,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown"); wwn2str(pwwn_buf, fcport->pwwn); if (BFA_PORT_IS_DISABLED(fcport->bfa)) - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port offline: WWN = %s\n", pwwn_buf); else - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Base port (WWN = %s) " "lost fabric connectivity\n", pwwn_buf); break; @@ -2349,10 +2349,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, bfa_fcport_reset_linkinfo(fcport); wwn2str(pwwn_buf, fcport->pwwn); if (BFA_PORT_IS_DISABLED(fcport->bfa)) - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port offline: WWN = %s\n", pwwn_buf); else - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Base port (WWN = %s) " "lost fabric connectivity\n", pwwn_buf); break; @@ -2363,10 +2363,10 @@ bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); wwn2str(pwwn_buf, fcport->pwwn); if (BFA_PORT_IS_DISABLED(fcport->bfa)) - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port offline: WWN = %s\n", pwwn_buf); else - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "Base port (WWN = %s) " "lost fabric connectivity\n", pwwn_buf); break; @@ -2497,7 +2497,7 @@ bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port enabled: WWN = %s\n", pwwn_buf); break; @@ -2551,7 +2551,7 @@ bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Base port enabled: WWN = %s\n", pwwn_buf); break; diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 1f938974b848..6797720213b2 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -50,7 +50,7 @@ int reqq_size, rspq_size, num_sgpgs; int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; int bfa_io_max_sge = BFAD_IO_MAX_SGE; -int log_level = 3; /* WARNING log level */ +int bfa_log_level = 3; /* WARNING log level */ int ioc_auto_recover = BFA_TRUE; int bfa_linkup_delay = -1; int fdmi_enable = BFA_TRUE; @@ -108,8 +108,8 @@ module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]"); module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255"); -module_param(log_level, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(log_level, "Driver log level, default=3, " +module_param(bfa_log_level, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, " "Range[Critical:1|Error:2|Warning:3|Info:4]"); module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, " @@ -1112,7 +1112,7 @@ bfad_start_ops(struct bfad_s *bfad) { } else bfad_os_rport_online_wait(bfad); - BFA_LOG(KERN_INFO, bfad, log_level, "bfa device claimed\n"); + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n"); return BFA_STATUS_OK; } diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 97f9b6c0937e..d5ce2349ac59 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -337,7 +337,7 @@ extern int num_sgpgs; extern int rport_del_timeout; extern int bfa_lun_queue_depth; extern int bfa_io_max_sge; -extern int log_level; +extern int bfa_log_level; extern int ioc_auto_recover; extern int bfa_linkup_delay; extern int msix_disable_cb; diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 8ca967dee66d..fbad5e9b2402 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -225,7 +225,8 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) } bfa_trc(bfad, hal_io->iotag); - BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n", + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "scsi%d: abort cmnd %p iotag %x\n", im_port->shost->host_no, cmnd, hal_io->iotag); (void) bfa_ioim_abort(hal_io); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -241,7 +242,7 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) cmnd->scsi_done(cmnd); bfa_trc(bfad, hal_io->iotag); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "scsi%d: complete abort 0x%p iotag 0x%x\n", im_port->shost->host_no, cmnd, hal_io->iotag); return SUCCESS; @@ -260,7 +261,7 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "target reset, fail to allocate tskim\n"); rc = BFA_STATUS_FAILED; goto out; @@ -311,7 +312,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "LUN reset, fail to allocate tskim"); spin_unlock_irqrestore(&bfad->bfad_lock, flags); rc = FAILED; @@ -336,7 +337,7 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "LUN reset failure, status: %d\n", task_status); rc = FAILED; } @@ -380,7 +381,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_LOG(KERN_ERR, bfad, log_level, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "target reset failure," " status: %d\n", task_status); err_cnt++; @@ -460,7 +461,7 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim); wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "ITNIM FREE scsi%d: FCID: %s WWPN: %s\n", port->im_port->shost->host_no, fcid_str, wwpn_str); @@ -589,7 +590,7 @@ void bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) { bfa_trc(bfad, bfad->inst_no); - BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n", + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n", im_port->shost->host_no); fc_remove_host(im_port->shost); @@ -1048,7 +1049,7 @@ bfad_im_itnim_work_handler(struct work_struct *work) fcid2str(fcid_str, fcid); list_add_tail(&itnim->list_entry, &im_port->itnim_mapped_list); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "ITNIM ONLINE Target: %d:0:%d " "FCID: %s WWPN: %s\n", im_port->shost->host_no, @@ -1081,7 +1082,7 @@ bfad_im_itnim_work_handler(struct work_struct *work) wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); list_del(&itnim->list_entry); - BFA_LOG(KERN_INFO, bfad, log_level, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "ITNIM OFFLINE Target: %d:0:%d " "FCID: %s WWPN: %s\n", im_port->shost->host_no, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 5b6bbaea59fe..4a3842212c50 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1637,9 +1637,8 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); - /* New queue, no concurrency on queue_flags */ if (!shost->use_clustering) - queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); + q->limits.cluster = 0; /* * set a reasonable default alignment on word boundaries: the diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 6ca7a44f29c2..e76d7d000128 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -7,6 +7,7 @@ * * Copyright 1999 ARM Limited * Copyright (C) 2000 Deep Blue Solutions Ltd. + * Copyright (C) 2010 ST-Ericsson SA * * 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 @@ -48,6 +49,9 @@ #include <linux/amba/serial.h> #include <linux/clk.h> #include <linux/slab.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/scatterlist.h> #include <asm/io.h> #include <asm/sizes.h> @@ -63,21 +67,6 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) -/* - * We wrap our port structure around the generic uart_port. - */ -struct uart_amba_port { - struct uart_port port; - struct clk *clk; - unsigned int im; /* interrupt mask */ - unsigned int old_status; - unsigned int ifls; /* vendor-specific */ - unsigned int lcrh_tx; /* vendor-specific */ - unsigned int lcrh_rx; /* vendor-specific */ - bool oversampling; /* vendor-specific */ - bool autorts; -}; - /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -85,6 +74,7 @@ struct vendor_data { unsigned int lcrh_tx; unsigned int lcrh_rx; bool oversampling; + bool dma_threshold; }; static struct vendor_data vendor_arm = { @@ -93,6 +83,7 @@ static struct vendor_data vendor_arm = { .lcrh_tx = UART011_LCRH, .lcrh_rx = UART011_LCRH, .oversampling = false, + .dma_threshold = false, }; static struct vendor_data vendor_st = { @@ -101,22 +92,535 @@ static struct vendor_data vendor_st = { .lcrh_tx = ST_UART011_LCRH_TX, .lcrh_rx = ST_UART011_LCRH_RX, .oversampling = true, + .dma_threshold = true, +}; + +/* Deals with DMA transactions */ +struct pl011_dmatx_data { + struct dma_chan *chan; + struct scatterlist sg; + char *buf; + bool queued; }; +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_amba_port { + struct uart_port port; + struct clk *clk; + const struct vendor_data *vendor; + unsigned int dmacr; /* dma control reg */ + unsigned int im; /* interrupt mask */ + unsigned int old_status; + unsigned int fifosize; /* vendor-specific */ + unsigned int lcrh_tx; /* vendor-specific */ + unsigned int lcrh_rx; /* vendor-specific */ + bool autorts; + char type[12]; +#ifdef CONFIG_DMA_ENGINE + /* DMA stuff */ + bool using_dma; + struct pl011_dmatx_data dmatx; +#endif +}; + +/* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, + * no custom DMA interfaces are supported. + */ +#ifdef CONFIG_DMA_ENGINE + +#define PL011_DMA_BUFFER_SIZE PAGE_SIZE + +static void pl011_dma_probe_initcall(struct uart_amba_port *uap) +{ + /* DMA is the sole user of the platform data right now */ + struct amba_pl011_data *plat = uap->port.dev->platform_data; + struct dma_slave_config tx_conf = { + .dst_addr = uap->port.mapbase + UART01x_DR, + .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, + .direction = DMA_TO_DEVICE, + .dst_maxburst = uap->fifosize >> 1, + }; + struct dma_chan *chan; + dma_cap_mask_t mask; + + /* We need platform data */ + if (!plat || !plat->dma_filter) { + dev_info(uap->port.dev, "no DMA platform data\n"); + return; + } + + /* Try to acquire a generic DMA engine slave channel */ + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param); + if (!chan) { + dev_err(uap->port.dev, "no TX DMA channel!\n"); + return; + } + + dmaengine_slave_config(chan, &tx_conf); + uap->dmatx.chan = chan; + + dev_info(uap->port.dev, "DMA channel TX %s\n", + dma_chan_name(uap->dmatx.chan)); +} + +#ifndef MODULE +/* + * Stack up the UARTs and let the above initcall be done at device + * initcall time, because the serial driver is called as an arch + * initcall, and at this time the DMA subsystem is not yet registered. + * At this point the driver will switch over to using DMA where desired. + */ +struct dma_uap { + struct list_head node; + struct uart_amba_port *uap; +}; + +static LIST_HEAD(pl011_dma_uarts); + +static int __init pl011_dma_initcall(void) +{ + struct list_head *node, *tmp; + + list_for_each_safe(node, tmp, &pl011_dma_uarts) { + struct dma_uap *dmau = list_entry(node, struct dma_uap, node); + pl011_dma_probe_initcall(dmau->uap); + list_del(node); + kfree(dmau); + } + return 0; +} + +device_initcall(pl011_dma_initcall); + +static void pl011_dma_probe(struct uart_amba_port *uap) +{ + struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL); + if (dmau) { + dmau->uap = uap; + list_add_tail(&dmau->node, &pl011_dma_uarts); + } +} +#else +static void pl011_dma_probe(struct uart_amba_port *uap) +{ + pl011_dma_probe_initcall(uap); +} +#endif + +static void pl011_dma_remove(struct uart_amba_port *uap) +{ + /* TODO: remove the initcall if it has not yet executed */ + if (uap->dmatx.chan) + dma_release_channel(uap->dmatx.chan); +} + + +/* Forward declare this for the refill routine */ +static int pl011_dma_tx_refill(struct uart_amba_port *uap); + +/* + * The current DMA TX buffer has been sent. + * Try to queue up another DMA buffer. + */ +static void pl011_dma_tx_callback(void *data) +{ + struct uart_amba_port *uap = data; + struct pl011_dmatx_data *dmatx = &uap->dmatx; + unsigned long flags; + u16 dmacr; + + spin_lock_irqsave(&uap->port.lock, flags); + if (uap->dmatx.queued) + dma_unmap_sg(dmatx->chan->device->dev, &dmatx->sg, 1, + DMA_TO_DEVICE); + + dmacr = uap->dmacr; + uap->dmacr = dmacr & ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + /* + * If TX DMA was disabled, it means that we've stopped the DMA for + * some reason (eg, XOFF received, or we want to send an X-char.) + * + * Note: we need to be careful here of a potential race between DMA + * and the rest of the driver - if the driver disables TX DMA while + * a TX buffer completing, we must update the tx queued status to + * get further refills (hence we check dmacr). + */ + if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) || + uart_circ_empty(&uap->port.state->xmit)) { + uap->dmatx.queued = false; + spin_unlock_irqrestore(&uap->port.lock, flags); + return; + } + + if (pl011_dma_tx_refill(uap) <= 0) { + /* + * We didn't queue a DMA buffer for some reason, but we + * have data pending to be sent. Re-enable the TX IRQ. + */ + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + } + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +/* + * Try to refill the TX DMA buffer. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * 1 if we queued up a TX DMA buffer. + * 0 if we didn't want to handle this by DMA + * <0 on error + */ +static int pl011_dma_tx_refill(struct uart_amba_port *uap) +{ + struct pl011_dmatx_data *dmatx = &uap->dmatx; + struct dma_chan *chan = dmatx->chan; + struct dma_device *dma_dev = chan->device; + struct dma_async_tx_descriptor *desc; + struct circ_buf *xmit = &uap->port.state->xmit; + unsigned int count; + + /* + * Try to avoid the overhead involved in using DMA if the + * transaction fits in the first half of the FIFO, by using + * the standard interrupt handling. This ensures that we + * issue a uart_write_wakeup() at the appropriate time. + */ + count = uart_circ_chars_pending(xmit); + if (count < (uap->fifosize >> 1)) { + uap->dmatx.queued = false; + return 0; + } + + /* + * Bodge: don't send the last character by DMA, as this + * will prevent XON from notifying us to restart DMA. + */ + count -= 1; + + /* Else proceed to copy the TX chars to the DMA buffer and fire DMA */ + if (count > PL011_DMA_BUFFER_SIZE) + count = PL011_DMA_BUFFER_SIZE; + + if (xmit->tail < xmit->head) + memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count); + else { + size_t first = UART_XMIT_SIZE - xmit->tail; + size_t second = xmit->head; + + memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first); + if (second) + memcpy(&dmatx->buf[first], &xmit->buf[0], second); + } + + dmatx->sg.length = count; + + if (dma_map_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE) != 1) { + uap->dmatx.queued = false; + dev_dbg(uap->port.dev, "unable to map TX DMA\n"); + return -EBUSY; + } + + desc = dma_dev->device_prep_slave_sg(chan, &dmatx->sg, 1, DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dma_unmap_sg(dma_dev->dev, &dmatx->sg, 1, DMA_TO_DEVICE); + uap->dmatx.queued = false; + /* + * If DMA cannot be used right now, we complete this + * transaction via IRQ and let the TTY layer retry. + */ + dev_dbg(uap->port.dev, "TX DMA busy\n"); + return -EBUSY; + } + + /* Some data to go along to the callback */ + desc->callback = pl011_dma_tx_callback; + desc->callback_param = uap; + + /* All errors should happen at prepare time */ + dmaengine_submit(desc); + + /* Fire the DMA transaction */ + dma_dev->device_issue_pending(chan); + + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + uap->dmatx.queued = true; + + /* + * Now we know that DMA will fire, so advance the ring buffer + * with the stuff we just dispatched. + */ + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + uap->port.icount.tx += count; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&uap->port); + + return 1; +} + +/* + * We received a transmit interrupt without a pending X-char but with + * pending characters. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * false if we want to use PIO to transmit + * true if we queued a DMA buffer + */ +static bool pl011_dma_tx_irq(struct uart_amba_port *uap) +{ + if (!uap->using_dma) + return false; + + /* + * If we already have a TX buffer queued, but received a + * TX interrupt, it will be because we've just sent an X-char. + * Ensure the TX DMA is enabled and the TX IRQ is disabled. + */ + if (uap->dmatx.queued) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + uap->im &= ~UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + return true; + } + + /* + * We don't have a TX buffer queued, so try to queue one. + * If we succesfully queued a buffer, mask the TX IRQ. + */ + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + return true; + } + return false; +} + +/* + * Stop the DMA transmit (eg, due to received XOFF). + * Locking: called with port lock held and IRQs disabled. + */ +static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) +{ + if (uap->dmatx.queued) { + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + } +} + +/* + * Try to start a DMA transmit, or in the case of an XON/OFF + * character queued for send, try to get that character out ASAP. + * Locking: called with port lock held and IRQs disabled. + * Returns: + * false if we want the TX IRQ to be enabled + * true if we have a buffer queued + */ +static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) +{ + u16 dmacr; + + if (!uap->using_dma) + return false; + + if (!uap->port.x_char) { + /* no X-char, try to push chars out in DMA mode */ + bool ret = true; + + if (!uap->dmatx.queued) { + if (pl011_dma_tx_refill(uap) > 0) { + uap->im &= ~UART011_TXIM; + ret = true; + } else { + uap->im |= UART011_TXIM; + ret = false; + } + writew(uap->im, uap->port.membase + UART011_IMSC); + } else if (!(uap->dmacr & UART011_TXDMAE)) { + uap->dmacr |= UART011_TXDMAE; + writew(uap->dmacr, + uap->port.membase + UART011_DMACR); + } + return ret; + } + + /* + * We have an X-char to send. Disable DMA to prevent it loading + * the TX fifo, and then see if we can stuff it into the FIFO. + */ + dmacr = uap->dmacr; + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { + /* + * No space in the FIFO, so enable the transmit interrupt + * so we know when there is space. Note that once we've + * loaded the character, we should just re-enable DMA. + */ + return false; + } + + writew(uap->port.x_char, uap->port.membase + UART01x_DR); + uap->port.icount.tx++; + uap->port.x_char = 0; + + /* Success - restore the DMA state */ + uap->dmacr = dmacr; + writew(dmacr, uap->port.membase + UART011_DMACR); + + return true; +} + +/* + * Flush the transmit buffer. + * Locking: called with port lock held and IRQs disabled. + */ +static void pl011_dma_flush_buffer(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + + if (!uap->using_dma) + return; + + /* Avoid deadlock with the DMA engine callback */ + spin_unlock(&uap->port.lock); + dmaengine_terminate_all(uap->dmatx.chan); + spin_lock(&uap->port.lock); + if (uap->dmatx.queued) { + dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, + DMA_TO_DEVICE); + uap->dmatx.queued = false; + uap->dmacr &= ~UART011_TXDMAE; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + } +} + + +static void pl011_dma_startup(struct uart_amba_port *uap) +{ + if (!uap->dmatx.chan) + return; + + uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); + if (!uap->dmatx.buf) { + dev_err(uap->port.dev, "no memory for DMA TX buffer\n"); + uap->port.fifosize = uap->fifosize; + return; + } + + sg_init_one(&uap->dmatx.sg, uap->dmatx.buf, PL011_DMA_BUFFER_SIZE); + + /* The DMA buffer is now the FIFO the TTY subsystem can use */ + uap->port.fifosize = PL011_DMA_BUFFER_SIZE; + uap->using_dma = true; + + /* Turn on DMA error (RX/TX will be enabled on demand) */ + uap->dmacr |= UART011_DMAONERR; + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + + /* + * ST Micro variants has some specific dma burst threshold + * compensation. Set this to 16 bytes, so burst will only + * be issued above/below 16 bytes. + */ + if (uap->vendor->dma_threshold) + writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, + uap->port.membase + ST_UART011_DMAWM); +} + +static void pl011_dma_shutdown(struct uart_amba_port *uap) +{ + if (!uap->using_dma) + return; + + /* Disable RX and TX DMA */ + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) + barrier(); + + spin_lock_irq(&uap->port.lock); + uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); + spin_unlock_irq(&uap->port.lock); + + /* In theory, this should already be done by pl011_dma_flush_buffer */ + dmaengine_terminate_all(uap->dmatx.chan); + if (uap->dmatx.queued) { + dma_unmap_sg(uap->dmatx.chan->device->dev, &uap->dmatx.sg, 1, + DMA_TO_DEVICE); + uap->dmatx.queued = false; + } + + kfree(uap->dmatx.buf); + + uap->using_dma = false; +} + +#else +/* Blank functions if the DMA engine is not available */ +static inline void pl011_dma_probe(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_remove(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_startup(struct uart_amba_port *uap) +{ +} + +static inline void pl011_dma_shutdown(struct uart_amba_port *uap) +{ +} + +static inline bool pl011_dma_tx_irq(struct uart_amba_port *uap) +{ + return false; +} + +static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) +{ +} + +static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) +{ + return false; +} + +#define pl011_dma_flush_buffer NULL +#endif + + static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; uap->im &= ~UART011_TXIM; writew(uap->im, uap->port.membase + UART011_IMSC); + pl011_dma_tx_stop(uap); } static void pl011_start_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; - uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); + if (!pl011_dma_tx_start(uap)) { + uap->im |= UART011_TXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + } } static void pl011_stop_rx(struct uart_port *port) @@ -203,7 +707,11 @@ static void pl011_tx_chars(struct uart_amba_port *uap) return; } - count = uap->port.fifosize >> 1; + /* If we are using DMA mode, try to send some characters. */ + if (pl011_dma_tx_irq(uap)) + return; + + count = uap->fifosize >> 1; do { writew(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -246,10 +754,11 @@ static void pl011_modem_status(struct uart_amba_port *uap) static irqreturn_t pl011_int(int irq, void *dev_id) { struct uart_amba_port *uap = dev_id; + unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; - spin_lock(&uap->port.lock); + spin_lock_irqsave(&uap->port.lock, flags); status = readw(uap->port.membase + UART011_MIS); if (status) { @@ -274,7 +783,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) handled = 1; } - spin_unlock(&uap->port.lock); + spin_unlock_irqrestore(&uap->port.lock, flags); return IRQ_RETVAL(handled); } @@ -396,7 +905,7 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(uap->ifls, uap->port.membase + UART011_IFLS); + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); /* * Provoke TX FIFO interrupt into asserting. @@ -423,11 +932,18 @@ static int pl011_startup(struct uart_port *port) cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; writew(cr, uap->port.membase + UART011_CR); + /* Clear pending error interrupts */ + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, + uap->port.membase + UART011_ICR); + /* * initialise the old status of the modem signals */ uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; + /* Startup DMA */ + pl011_dma_startup(uap); + /* * Finally, enable interrupts */ @@ -467,6 +983,8 @@ static void pl011_shutdown(struct uart_port *port) writew(0xffff, uap->port.membase + UART011_ICR); spin_unlock_irq(&uap->port.lock); + pl011_dma_shutdown(uap); + /* * Free the interrupt */ @@ -498,13 +1016,18 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct uart_amba_port *uap = (struct uart_amba_port *)port; unsigned int lcr_h, old_cr; unsigned long flags; - unsigned int baud, quot; + unsigned int baud, quot, clkdiv; + + if (uap->vendor->oversampling) + clkdiv = 8; + else + clkdiv = 16; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, - port->uartclk/(uap->oversampling ? 8 : 16)); + port->uartclk / clkdiv); if (baud > port->uartclk/16) quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); @@ -532,7 +1055,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, if (!(termios->c_cflag & PARODD)) lcr_h |= UART01x_LCRH_EPS; } - if (port->fifosize > 1) + if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; spin_lock_irqsave(&port->lock, flags); @@ -588,8 +1111,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, uap->autorts = false; } - if (uap->oversampling) { - if (baud > port->uartclk/16) + if (uap->vendor->oversampling) { + if (baud > port->uartclk / 16) old_cr |= ST_UART011_CR_OVSFACT; else old_cr &= ~ST_UART011_CR_OVSFACT; @@ -622,7 +1145,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, static const char *pl011_type(struct uart_port *port) { - return port->type == PORT_AMBA ? "AMBA/PL011" : NULL; + struct uart_amba_port *uap = (struct uart_amba_port *)port; + return uap->port.type == PORT_AMBA ? uap->type : NULL; } /* @@ -679,6 +1203,7 @@ static struct uart_ops amba_pl011_pops = { .break_ctl = pl011_break_ctl, .startup = pl011_startup, .shutdown = pl011_shutdown, + .flush_buffer = pl011_dma_flush_buffer, .set_termios = pl011_set_termios, .type = pl011_type, .release_port = pl010_release_port, @@ -761,7 +1286,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); - if (uap->oversampling) { + if (uap->vendor->oversampling) { if (readw(uap->port.membase + UART011_CR) & ST_UART011_CR_OVSFACT) *baud *= 2; @@ -858,19 +1383,22 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) goto unmap; } - uap->ifls = vendor->ifls; + uap->vendor = vendor; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; - uap->oversampling = vendor->oversampling; + uap->fifosize = vendor->fifosize; uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; uap->port.iotype = UPIO_MEM; uap->port.irq = dev->irq[0]; - uap->port.fifosize = vendor->fifosize; + uap->port.fifosize = uap->fifosize; uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = i; + pl011_dma_probe(uap); + + snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); amba_ports[i] = uap; @@ -879,6 +1407,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id) if (ret) { amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; + pl011_dma_remove(uap); clk_put(uap->clk); unmap: iounmap(base); @@ -902,6 +1431,7 @@ static int pl011_remove(struct amba_device *dev) if (amba_ports[i] == uap) amba_ports[i] = NULL; + pl011_dma_remove(uap); iounmap(uap->port.membase); clk_put(uap->clk); kfree(uap); diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index e5e9e6735f7d..9739431092d1 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -198,6 +198,7 @@ int __init register_intc_controller(struct intc_desc *desc) list_add_tail(&d->list, &intc_list); raw_spin_lock_init(&d->lock); + INIT_RADIX_TREE(&d->tree, GFP_ATOMIC); d->index = nr_intc_controllers; diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c index 052b3c7fa6a0..8856bcca9d29 100644 --- a/drivers/spi/coldfire_qspi.c +++ b/drivers/spi/coldfire_qspi.c @@ -317,7 +317,7 @@ static void mcfqspi_work(struct work_struct *work) msg = container_of(mcfqspi->msgq.next, struct spi_message, queue); - list_del_init(&mcfqspi->msgq); + list_del_init(&msg->queue); spin_unlock_irqrestore(&mcfqspi->lock, flags); spi = msg->spi; diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c index ec9f0b1bf864..84439f655601 100644 --- a/drivers/spi/mpc52xx_spi.c +++ b/drivers/spi/mpc52xx_spi.c @@ -563,7 +563,7 @@ static struct of_platform_driver mpc52xx_spi_of_driver = { .of_match_table = mpc52xx_spi_match, }, .probe = mpc52xx_spi_probe, - .remove = __exit_p(mpc52xx_spi_remove), + .remove = __devexit_p(mpc52xx_spi_remove), }; static int __init mpc52xx_spi_init(void) diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 2a651e61bfbf..951a160fc27f 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -1305,10 +1305,49 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:omap2_mcspi"); +#ifdef CONFIG_SUSPEND +/* + * When SPI wake up from off-mode, CS is in activate state. If it was in + * unactive state when driver was suspend, then force it to unactive state at + * wake up. + */ +static int omap2_mcspi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + struct omap2_mcspi_cs *cs; + + omap2_mcspi_enable_clocks(mcspi); + list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs, + node) { + if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { + + /* + * We need to toggle CS state for OMAP take this + * change in account. + */ + MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1); + __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); + MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0); + __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); + } + } + omap2_mcspi_disable_clocks(mcspi); + return 0; +} +#else +#define omap2_mcspi_resume NULL +#endif + +static const struct dev_pm_ops omap2_mcspi_pm_ops = { + .resume = omap2_mcspi_resume, +}; + static struct platform_driver omap2_mcspi_driver = { .driver = { .name = "omap2_mcspi", .owner = THIS_MODULE, + .pm = &omap2_mcspi_pm_ops }, .remove = __exit_p(omap2_mcspi_remove), }; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 709c836607de..b02d0cbce890 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -584,8 +584,7 @@ void spi_unregister_master(struct spi_master *master) list_del(&master->list); mutex_unlock(&board_lock); - dummy = device_for_each_child(master->dev.parent, &master->dev, - __unregister); + dummy = device_for_each_child(&master->dev, NULL, __unregister); device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c index e3b4f6451966..a99e2333b949 100644 --- a/drivers/spi/spi_fsl_espi.c +++ b/drivers/spi/spi_fsl_espi.c @@ -258,18 +258,18 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) return mpc8xxx_spi->count; } -static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd) +static inline void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd) { - if (cmd[1] && cmd[2] && cmd[3]) { + if (cmd) { cmd[1] = (u8)(addr >> 16); cmd[2] = (u8)(addr >> 8); cmd[3] = (u8)(addr >> 0); } } -static unsigned int fsl_espi_cmd2addr(u8 *cmd) +static inline unsigned int fsl_espi_cmd2addr(u8 *cmd) { - if (cmd[1] && cmd[2] && cmd[3]) + if (cmd) return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0; return 0; @@ -395,9 +395,11 @@ static void fsl_espi_rw_trans(struct spi_message *m, } } - addr = fsl_espi_cmd2addr(local_buf); - addr += pos; - fsl_espi_addr2cmd(addr, local_buf); + if (pos > 0) { + addr = fsl_espi_cmd2addr(local_buf); + addr += pos; + fsl_espi_addr2cmd(addr, local_buf); + } espi_trans->n_tx = n_tx; espi_trans->n_rx = trans_len; @@ -507,16 +509,29 @@ void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events) /* We need handle RX first */ if (events & SPIE_NE) { - u32 rx_data; + u32 rx_data, tmp; + u8 rx_data_8; /* Spin until RX is done */ while (SPIE_RXCNT(events) < min(4, mspi->len)) { cpu_relax(); events = mpc8xxx_spi_read_reg(®_base->event); } - mspi->len -= 4; - rx_data = mpc8xxx_spi_read_reg(®_base->receive); + if (mspi->len >= 4) { + rx_data = mpc8xxx_spi_read_reg(®_base->receive); + } else { + tmp = mspi->len; + rx_data = 0; + while (tmp--) { + rx_data_8 = in_8((u8 *)®_base->receive); + rx_data |= (rx_data_8 << (tmp * 8)); + } + + rx_data <<= (4 - mspi->len) * 8; + } + + mspi->len -= 4; if (mspi->rx) mspi->get_rx(rx_data, mspi); diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c index e7f1d5778cec..52389308f333 100644 --- a/drivers/staging/cx25821/cx25821-video.c +++ b/drivers/staging/cx25821/cx25821-video.c @@ -92,7 +92,7 @@ int cx25821_get_format_size(void) return ARRAY_SIZE(formats); } -struct cx25821_fmt *format_by_fourcc(unsigned int fourcc) +struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -848,7 +848,7 @@ static int video_open(struct file *file) pix_format = (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411) ? V4L2_PIX_FMT_Y41P : V4L2_PIX_FMT_YUYV; - fh->fmt = format_by_fourcc(pix_format); + fh->fmt = cx25821_format_by_fourcc(pix_format); v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); @@ -1010,7 +1010,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); fh->vidq.field = f->fmt.pix.field; /* check if width and height is valid based on set standard */ @@ -1119,7 +1119,7 @@ int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fo enum v4l2_field field; unsigned int maxw, maxh; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/staging/cx25821/cx25821-video.h index cc6034b1a95d..a2415d33235b 100644 --- a/drivers/staging/cx25821/cx25821-video.h +++ b/drivers/staging/cx25821/cx25821-video.h @@ -87,7 +87,7 @@ extern unsigned int vid_limit; #define FORMAT_FLAGS_PACKED 0x01 extern struct cx25821_fmt formats[]; -extern struct cx25821_fmt *format_by_fourcc(unsigned int fourcc); +extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; extern void cx25821_dump_video_queue(struct cx25821_dev *dev, diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 8c3c057aa847..d0e9e0207539 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -435,12 +435,6 @@ static int zram_make_request(struct request_queue *queue, struct bio *bio) int ret = 0; struct zram *zram = queue->queuedata; - if (unlikely(!zram->init_done)) { - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio_endio(bio, 0); - return 0; - } - if (!valid_io_request(zram, bio)) { zram_stat64_inc(zram, &zram->stats.invalid_io); bio_io_error(bio); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 81b46585edf7..c5f8e5bda2b2 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -716,8 +716,8 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) if (msg->len < 128) *--dp = (msg->len << 1) | EA; else { - *--dp = ((msg->len & 127) << 1) | EA; - *--dp = (msg->len >> 6) & 0xfe; + *--dp = (msg->len >> 7); /* bits 7 - 15 */ + *--dp = (msg->len & 127) << 1; /* bits 0 - 6 */ } } @@ -968,6 +968,8 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, { struct gsm_msg *msg; msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype); + if (msg == NULL) + return; msg->data[0] = (cmd & 0xFE) << 1 | EA; /* Clear C/R */ msg->data[1] = (dlen << 1) | EA; memcpy(msg->data + 2, data, dlen); diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 44447f54942f..99ac70e32556 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2206,8 +2206,11 @@ static int uea_boot(struct uea_softc *sc) goto err1; } - sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); - if (sc->kthread == ERR_PTR(-ENOMEM)) { + /* Create worker thread, but don't start it here. Start it after + * all usbatm generic initialization is done. + */ + sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); + if (IS_ERR(sc->kthread)) { uea_err(INS_TO_USBDEV(sc), "failed to create thread\n"); goto err2; } @@ -2624,6 +2627,7 @@ static struct usbatm_driver uea_usbatm_driver = { static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usb = interface_to_usbdev(intf); + int ret; uea_enters(usb); uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", @@ -2637,7 +2641,19 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) if (UEA_IS_PREFIRM(id)) return uea_load_firmware(usb, UEA_CHIP_VERSION(id)); - return usbatm_usb_probe(intf, id, &uea_usbatm_driver); + ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver); + if (ret == 0) { + struct usbatm_data *usbatm = usb_get_intfdata(intf); + struct uea_softc *sc = usbatm->driver_data; + + /* Ensure carrier is initialized to off as early as possible */ + UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST); + + /* Only start the worker thread when all init is done */ + wake_up_process(sc->kthread); + } + + return ret; } static void uea_disconnect(struct usb_interface *intf) diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 9eed5b52d9de..bcc24779ba0e 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -107,11 +107,19 @@ config USB_SUSPEND If you are unsure about this, say N here. config USB_OTG - bool + bool "OTG support" depends on USB && EXPERIMENTAL depends on USB_SUSPEND default n - + help + The most notable feature of USB OTG is support for a + "Dual-Role" device, which can act as either a device + or a host. The initial role is decided by the type of + plug inserted and can be changed later when two dual + role devices talk to each other. + + Select this only if your board has Mini-AB/Micro-AB + connector. config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 7b5cc16e4a0b..8572dad5ecbb 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1047,9 +1047,9 @@ composite_unbind(struct usb_gadget *gadget) kfree(cdev->req->buf); usb_ep_free_request(gadget->ep0, cdev->req); } + device_remove_file(&gadget->dev, &dev_attr_suspended); kfree(cdev); set_gadget_data(gadget, NULL); - device_remove_file(&gadget->dev, &dev_attr_suspended); composite = NULL; } @@ -1107,14 +1107,6 @@ static int composite_bind(struct usb_gadget *gadget) */ usb_ep_autoconfig_reset(cdev->gadget); - /* standardized runtime overrides for device ID data */ - if (idVendor) - cdev->desc.idVendor = cpu_to_le16(idVendor); - if (idProduct) - cdev->desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); - /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc @@ -1126,6 +1118,14 @@ static int composite_bind(struct usb_gadget *gadget) cdev->desc = *composite->dev; cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + /* standardized runtime overrides for device ID data */ + if (idVendor) + cdev->desc.idVendor = cpu_to_le16(idVendor); + if (idProduct) + cdev->desc.idProduct = cpu_to_le16(idProduct); + if (bcdDevice) + cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + /* stirng overrides */ if (iManufacturer || !cdev->desc.iManufacturer) { if (!iManufacturer && !composite->iManufacturer && diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 0fae58ef8afe..1d0f45f0e7a6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1680,6 +1680,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, xhci->port_array[i] = (u8) -1; } /* FIXME: Should we disable the port? */ + continue; } xhci->port_array[i] = major_revision; if (major_revision == 0x03) @@ -1758,16 +1759,20 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) return -ENOMEM; port_index = 0; - for (i = 0; i < num_ports; i++) - if (xhci->port_array[i] != 0x03) { - xhci->usb2_ports[port_index] = - &xhci->op_regs->port_status_base + - NUM_PORT_REGS*i; - xhci_dbg(xhci, "USB 2.0 port at index %u, " - "addr = %p\n", i, - xhci->usb2_ports[port_index]); - port_index++; - } + for (i = 0; i < num_ports; i++) { + if (xhci->port_array[i] == 0x03 || + xhci->port_array[i] == 0 || + xhci->port_array[i] == -1) + continue; + + xhci->usb2_ports[port_index] = + &xhci->op_regs->port_status_base + + NUM_PORT_REGS*i; + xhci_dbg(xhci, "USB 2.0 port at index %u, " + "addr = %p\n", i, + xhci->usb2_ports[port_index]); + port_index++; + } } if (xhci->num_usb3_ports) { xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 796e2f68f749..4ff21587ab03 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -3,7 +3,7 @@ /* * uss720.c -- USS720 USB Parport Cable. * - * Copyright (C) 1999, 2005 + * Copyright (C) 1999, 2005, 2010 * Thomas Sailer (t.sailer@alumni.ethz.ch) * * This program is free software; you can redistribute it and/or modify @@ -776,6 +776,8 @@ static const struct usb_device_id uss720_table[] = { { USB_DEVICE(0x0557, 0x2001) }, { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, + { USB_DEVICE(0x1293, 0x0002) }, + { USB_DEVICE(0x050d, 0x0002) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6a50965e23f2..2dec50013528 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -796,6 +796,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { }, /* Optional parameter entry */ diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 1286f1e23d8c..bf0867285481 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1081,6 +1081,11 @@ #define MJSG_HD_RADIO_PID 0x937C /* + * D.O.Tec products (http://www.directout.eu) + */ +#define FTDI_DOTEC_PID 0x9868 + +/* * Xverve Signalyzer tools (http://www.signalyzer.com/) */ #define XVERVE_SIGNALYZER_ST_PID 0xBCA0 diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 6ccdd3dd5259..fcc1e32ce256 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -481,6 +481,13 @@ UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64), +/* Reported by Vitaly Kuznetsov <vitty@altlinux.ru> */ +UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999, + "Samsung", + "YP-CP3", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG), + /* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>. * Device uses standards-violating 32-byte Bulk Command Block Wrappers and * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011. diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index a4f4546f0be0..397d15eb1ea8 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -242,6 +242,7 @@ static int cr_backlight_remove(struct platform_device *pdev) backlight_device_unregister(crp->cr_backlight_device); lcd_device_unregister(crp->cr_lcd_device); pci_dev_put(lpc_dev); + kfree(crp); return 0; } diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 0e6aa3d96a42..4ac1201ad6c2 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1458,7 +1458,7 @@ static bool apertures_overlap(struct aperture *gen, struct aperture *hw) if (gen->base == hw->base) return true; /* is the generic aperture base inside the hw base->hw base+size */ - if (gen->base > hw->base && gen->base <= hw->base + hw->size) + if (gen->base > hw->base && gen->base < hw->base + hw->size) return true; return false; } diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 5c363d026f64..1ab2c2588675 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -53,11 +53,8 @@ #define LCDC_SIZE 0x04 #define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20) -#ifdef CONFIG_ARCH_MX1 -#define SIZE_YMAX(y) ((y) & 0x1ff) -#else -#define SIZE_YMAX(y) ((y) & 0x3ff) -#endif +#define YMAX_MASK (cpu_is_mx1() ? 0x1ff : 0x3ff) +#define SIZE_YMAX(y) ((y) & YMAX_MASK) #define LCDC_VPW 0x08 #define VPW_VPW(x) ((x) & 0x3ff) @@ -623,7 +620,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf if (var->right_margin > 255) printk(KERN_ERR "%s: invalid right_margin %d\n", info->fix.id, var->right_margin); - if (var->yres < 1 || var->yres > 511) + if (var->yres < 1 || var->yres > YMAX_MASK) printk(KERN_ERR "%s: invalid yres %d\n", info->fix.id, var->yres); if (var->vsync_len > 100) diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 455c6055325d..083c8fe53e24 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -1,7 +1,7 @@ config FB_OMAP tristate "OMAP frame buffer support (EXPERIMENTAL)" - depends on FB && ARCH_OMAP && (OMAP2_DSS = "n") - + depends on FB && (OMAP2_DSS = "n") + depends on ARCH_OMAP1 || ARCH_OMAP2 || ARCH_OMAP3 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c index 2fd7e5271be9..9441e2eb3dee 100644 --- a/drivers/video/omap2/vram.c +++ b/drivers/video/omap2/vram.c @@ -551,7 +551,7 @@ void __init omap_vram_reserve_sdram_memblock(void) if (!size) return; - size = PAGE_ALIGN(size); + size = ALIGN(size, SZ_2M); if (paddr) { if (paddr & ~PAGE_MASK) { @@ -576,7 +576,7 @@ void __init omap_vram_reserve_sdram_memblock(void) return; } } else { - paddr = memblock_alloc(size, PAGE_SIZE); + paddr = memblock_alloc(size, SZ_2M); } memblock_free(paddr, size); diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index d7df10315d8d..fcda0e970113 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -787,6 +787,9 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) found_rate_error = rate_error; } + hdmi->var.width = hdmi->monspec.max_x * 10; + hdmi->var.height = hdmi->monspec.max_y * 10; + /* * TODO 1: if no ->info is present, postpone running the config until * after ->info first gets registered. @@ -960,8 +963,12 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", mode1.xres, mode1.yres, mode2.xres, mode2.yres); - if (fb_mode_is_equal(&mode1, &mode2)) + if (fb_mode_is_equal(&mode1, &mode2)) { + /* It can be a different monitor with an equal video-mode */ + old_var->width = new_var->width; + old_var->height = new_var->height; return false; + } dev_dbg(info->dev, "Switching %u -> %u lines\n", mode1.yres, mode2.yres); @@ -1057,8 +1064,11 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) * on, if we run a resume here, the logo disappears */ if (lock_fb_info(hdmi->info)) { - sh_hdmi_display_on(hdmi, hdmi->info); - unlock_fb_info(hdmi->info); + struct fb_info *info = hdmi->info; + info->var.width = hdmi->var.width; + info->var.height = hdmi->var.height; + sh_hdmi_display_on(hdmi, info); + unlock_fb_info(info); } } else { /* New monitor or have to wake up */ diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index b02d97a879d6..c05326b61235 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) -#define DEFAULT_XRES 1280 -#define DEFAULT_YRES 1024 +#define MAX_XRES 1920 +#define MAX_YRES 1080 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, @@ -914,22 +914,12 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in { struct sh_mobile_lcdc_chan *ch = info->par; - if (var->xres < 160 || var->xres > 1920 || - var->yres < 120 || var->yres > 1080 || - var->left_margin < 32 || var->left_margin > 320 || - var->right_margin < 12 || var->right_margin > 240 || - var->upper_margin < 12 || var->upper_margin > 120 || - var->lower_margin < 1 || var->lower_margin > 64 || - var->hsync_len < 32 || var->hsync_len > 240 || - var->vsync_len < 2 || var->vsync_len > 64 || - var->pixclock < 6000 || var->pixclock > 40000 || + if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { - dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", - var->xres, var->yres, - var->left_margin, var->right_margin, - var->upper_margin, var->lower_margin, - var->hsync_len, var->vsync_len, - var->pixclock); + dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n", + var->left_margin, var->xres, var->right_margin, var->hsync_len, + var->upper_margin, var->yres, var->lower_margin, var->vsync_len, + PICOS2KHZ(var->pixclock)); return -EINVAL; } return 0; @@ -1226,7 +1216,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } if (!mode) - max_size = DEFAULT_XRES * DEFAULT_YRES; + max_size = MAX_XRES * MAX_YRES; else if (max_cfg) dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", max_cfg->xres, max_cfg->yres); @@ -1238,12 +1228,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) mode = &default_720p; num_cfg = 1; } else { - num_cfg = ch->cfg.num_cfg; + num_cfg = cfg->num_cfg; } fb_videomode_to_modelist(mode, num_cfg, &info->modelist); fb_videomode_to_var(var, mode); + var->width = cfg->lcd_size_cfg.width; + var->height = cfg->lcd_size_cfg.height; /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; var->activate = FB_ACTIVATE_NOW; diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c index 428f8a1583e8..3939e53f5f98 100644 --- a/drivers/watchdog/rdc321x_wdt.c +++ b/drivers/watchdog/rdc321x_wdt.c @@ -231,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) struct resource *r; struct rdc321x_wdt_pdata *pdata; - pdata = pdev->dev.platform_data; + pdata = platform_get_drvdata(pdev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; |